题目链接 ZOJ Monthly, March 2018 Problem F
题意很明确
这个模数很奇妙,在$[0, mod)$的所有数满足任意一个数立方$48$次对$mod$取模之后会回到本身。
所以开$48$棵线段树,和一个永久标记。当对某个区间操作时对这个区间加一层永久标记。
即当前我要查找的第$x$层,实际找的是第$up[i] + x$层。
时间复杂度$O(48nlogn)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define ls i << 1 #define rs i << 1 | 1 #define mid ((l + r) >> 1) #define lson ls, l, mid #define rson rs, mid + 1, r typedef long long LL; const int N = 1e5 + 10; const int mod = 99971; int T; int a[N], nxt[N], cal[N][49]; int t[N << 2][49], up[N << 2]; int n, m; void pushup(int i){ rep(j, 0, 47){ t[i][j] = t[ls][(j + up[ls] + 48) % 48] + t[rs][(j + up[rs] + 48) % 48]; t[i][j] %= mod; } } void build(int i, int l, int r){ up[i] = 0; if (l == r){ rep(j, 0, 47) t[i][j] = cal[a[l]][j]; return; } build(lson); build(rson); pushup(i); } void update(int i, int l, int r, int L, int R){ if (L <= l && r <= R){ ++up[i]; up[i] %= 48; return; } if (L <= mid) update(lson, L, R); if (R > mid) update(rson, L, R); pushup(i); } int query(int i, int l, int r, int L, int R, int cnt){ if (L <= l && r <= R){ return t[i][(up[i] + cnt) % 48]; } int ret = 0; int now = cnt + up[i]; if (L <= mid) ret += query(lson, L, R, now); if (R > mid) ret += query(rson, L, R, now); ret %= mod; return ret; } int main(){ scanf("%d", &T); rep(i, 1, mod - 1) nxt[i] = 1ll * i * i * i % mod; rep(i, 1, mod - 1){ cal[i][0] = i; rep(j, 1, 47){ cal[i][j] = nxt[cal[i][j - 1]]; } } while (T--){ scanf("%d%d", &n, &m); rep(i, 1, n){ scanf("%d", a + i); a[i] %= mod; } build(1, 1, n); while (m--){ int op, l, r; scanf("%d%d%d", &op, &l, &r); if (op == 1) update(1, 1, n, l, r); else printf("%d ", query(1, 1, n, l, r, 0)); } } return 0; }