题解:P7131 「RdOI R1」变换(turn)
weilycoder · · 题解
法 1
题目要求的实际上就是这样的函数的复合:
所以我们求一下
注意到函数始终是
但是由于复合后的 long double 乱搞一下。
我们把函数写成
上线段树即可。
法 2
观察一下
由于
若
若
这个玩意不好和其他函数复合,不妨把它写成
容易证明在
上线段树维护。
Code
这是方法 1 的代码,被 Hack 了叫我一声,有 dalao 证明正确了也叫我一声。
#include <cmath>
#include <iostream>
using namespace std;
const int N = 1e5 + 7;
int n, m, P[N], Q[N];
struct node_t {
long double a, b;
inline node_t operator*(const node_t &g) const {
return {a * g.a, g.b / a + b};
}
inline int64_t operator()(int x) const { return floorl(x / a + b); }
} tree[N << 2];
#define lc (p << 1)
#define rc (p << 1 | 1)
void build(int p, int l, int r) {
if (l == r) {
tree[p] = {(long double)P[l], (long double)Q[l]};
return;
}
int mid = ((r - l) >> 1) + l;
build(lc, l, mid), build(rc, mid + 1, r);
tree[p] = tree[rc] * tree[lc];
}
void update(int p, int l, int r, int x, int a, int b) {
if (l == r) {
tree[p] = {(long double)a, (long double)b};
return;
}
int mid = ((r - l) >> 1) + l;
if (x <= mid)
update(lc, l, mid, x, a, b);
else
update(rc, mid + 1, r, x, a, b);
tree[p] = tree[rc] * tree[lc];
}
node_t ask(int p, int l, int r, int s, int t) {
if (s <= l && r <= t)
return tree[p];
int mid = ((r - l) >> 1) + l;
node_t res{(long double)1, (long double)0};
if (s <= mid)
res = ask(lc, l, mid, s, t) * res;
if (t > mid)
res = ask(rc, mid + 1, r, s, t) * res;
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> P[i];
for (int i = 1; i <= n; ++i)
cin >> Q[i];
build(1, 1, n);
while (m--) {
char op;
cin >> op;
switch (op) {
case 'm': {
int i, p, q;
cin >> i >> p >> q;
update(1, 1, n, i, p, q);
break;
}
case 'q': {
int x, s, t;
cin >> x >> s >> t;
cout << ask(1, 1, n, s, t)(x) << '\n';
}
}
}
return 0;
}