P8878 题解
由于值域较小,考虑一个值域相关的算法。
对于每次操作,我们可以预先算出在该操作下每个
预处理
随后以标记合并方式维护即可。标记合并的复杂度为
因此我们可以在
采用分块可以获得复杂度
参考代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, R = 105;
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
int n, q, a[N], l, r, k, p, c, f[R][R][R];
struct permu {
static const int len = 100;
int p[R];
permu() { iota(p, p + R, 0); }
int operator[] (const int &i) const { return p[i]; }
int &operator[] (const int &i) { return p[i]; }
permu &operator *= (const permu &rhs) {
for (int i = 0; i <= len; i++)
p[i] = rhs[p[i]];
return *this;
}
permu operator* (const permu &rhs) const {
permu _(*this);
return _ *= rhs;
}
} id, per;
struct SMT {
#define ls (p << 1)
#define rs (p << 1 | 1)
permu tr[N << 2];
inline void ps_d(const int& p) {
tr[ls] *= tr[p];
tr[rs] *= tr[p];
tr[p] = id;
}
void assign(int p, int l, int r, int L, int R, const permu& pr) {
if (L <= l and r <= R) {
tr[p] *= pr;
return;
} ps_d(p); int mid = l + r >> 1;
if (L <= mid) assign(ls, l, mid, L, R, pr);
if (mid < R) assign(rs, mid+1, r, L, R, pr);
}
void print(int p, int l, int r) {
if (l == r) {
printf("%d ", tr[p][a[l]]);
return;
} ps_d(p); int mid = l + r >> 1;
print(ls, l, mid);
print(rs, mid+1, r);
}
#undef rs
#undef ls
} T;
int main() {
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
rep(i,2,100) rep(j,1,100) f[1][i][j] = 1;
rep(i,2,100) rep(j,1,100) {
f[i][j][1] = (f[i - 1][j][1] + f[i - 2][j][1]) % j;
rep(k,2,100) f[i][j][k] = f[i][j][k - 1] * f[i][j][1] % j;
}
while (q--) {
cin >> l >> r >> k >> p >> c;
rep(i,0,100) per[i] = (f[i][p][k] + c) % p;
T.assign(1, 1, n, l, r, per);
}
T.print(1, 1, n);
}