首先嘛这道题目只要知道一个东西就很容易了:所有循环的最小公约数<=60,成一条链的长度最大为11,那么我们就可以用一个很裸的方法。对于在链上的数,我们修改直接暴力找出并修改。对于在环上的数,我们对每一步建立一颗线段树,那么修改就变成了交换60棵线段树的某个子树。然后我们就可以愉快的写啦~~~
在想的时候被同学坑了,他说最长的循环不超过60.。。。
在实现方面,我用一个map+树状数组维护链上的答案,然后用60棵线段树来维护这个环。懂了之后还是很好写哒~~~
Code:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int N = 100000 + 10, kCycle = 60 + 10; 6 7 int n, m, p, x[N]; 8 9 int dist[N], cycle = 1; 10 11 inline int GCD(int a, int b) { return b ? GCD(b, a % b) : a; } 12 inline int LCM(int a, int b) { return a * b / GCD(a, b); } 13 14 int pre[N]; 15 16 void Analysis(int a) { 17 dist[a] = -2; 18 int b = a * a % p; 19 if (dist[b] == -1) { 20 pre[b] = a; 21 Analysis(b); 22 } else if (dist[b] == -2) { 23 int cnt = 1; 24 for (int i = a; i != b; i = pre[i], ++cnt) dist[i] = 0; 25 dist[b] = 0; 26 cycle = LCM(cycle, cnt); 27 } 28 if (dist[a] == -2) dist[a] = dist[b] + 1; 29 } 30 31 inline int pos(int l, int r) { return (l + r) | (l != r); } 32 33 int tree[N * 2][kCycle], shift[N * 2]; 34 35 inline void Merge(int u[], int a[], int b[]) { 36 for (int i = 0; i < cycle; ++i) u[i] = a[i] + b[i]; 37 } 38 39 inline void Shift(int id, int v) { 40 static int temp[kCycle * 2]; 41 (shift[id] += v) %= cycle; 42 for (int i = 0; i < cycle; ++i) temp[i] = tree[id][(i + v) % cycle]; 43 std::copy(temp, temp + cycle, tree[id]); 44 } 45 46 void Modify(int l, int r, int u, int v) { 47 int id = pos(l, r); 48 for (int i = 0; i < cycle; ++i, (v *= v) %= p) tree[id][i] += v; 49 if (l == r) return; 50 int mid = (l + r) / 2; 51 if (shift[id]) { 52 Shift(pos(l, mid), shift[id]); 53 Shift(pos(mid + 1, r), shift[id]); 54 shift[id] = 0; 55 } 56 if (u <= mid) Modify(l, mid, u, v); else Modify(mid + 1, r, u, v); 57 } 58 59 void Cycle(int l, int r, int u, int v) { 60 int id = pos(l, r); 61 if (u <= l && r <= v) { 62 Shift(id, 1); 63 return; 64 } 65 int mid = (l + r) / 2; 66 if (shift[id]) { 67 Shift(pos(l, mid), shift[id]); 68 Shift(pos(mid + 1, r), shift[id]); 69 shift[id] = 0; 70 } 71 if (u <= mid) Cycle(l, mid, u, v); 72 if (v > mid) Cycle(mid + 1, r, u, v); 73 Merge(tree[id], tree[pos(l, mid)], tree[pos(mid + 1, r)]); 74 } 75 76 int Query(int l, int r, int u, int v) { 77 int id = pos(l, r); 78 if (u <= l && r <= v) return tree[id][0]; 79 int mid = (l + r) / 2, res = 0; 80 if (shift[id]) { 81 Shift(pos(l, mid), shift[id]); 82 Shift(pos(mid + 1, r), shift[id]); 83 shift[id] = 0; 84 } 85 if (u <= mid) res += Query(l, mid, u, v); 86 if (v > mid) res += Query(mid + 1, r, u, v); 87 return res; 88 } 89 90 class BIT { 91 int data[N]; 92 93 public: 94 inline void Add(int p, int v) { for (; p <= n; p += p & -p) data[p] += v; } 95 inline int Query(int p) { 96 int res = 0; 97 for (; p; p ^= p & -p) res += data[p]; 98 return res; 99 } 100 inline int Query(int l, int r) { return Query(r) - Query(l - 1); } 101 102 } cnt, sum; 103 104 void Sqr(int l, int r) { 105 if (!cnt.Query(l, r)) return; 106 if (l == r) { 107 cnt.Add(l, -1); 108 sum.Add(l, -x[l]); 109 if (cnt.Query(l, l) == 0) 110 Modify(1, n, l, (x[l] *= x[l]) %= p); 111 else 112 sum.Add(l, (x[l] *= x[l]) %= p); 113 } else { 114 int mid = (l + r) / 2; 115 Sqr(l, mid); 116 Sqr(mid + 1, r); 117 } 118 } 119 120 int main() { 121 scanf("%d%d%d", &n, &m, &p); 122 for (int i = 1; i <= n; ++i) scanf("%d", x + i); 123 memset(dist, -1, sizeof dist); 124 for (int i = 0; i < p; ++i) if (dist[i] == -1) Analysis(i); 125 for (int i = 1; i <= n; ++i) { 126 if (dist[x[i]]) { 127 sum.Add(i, x[i]); 128 cnt.Add(i, dist[x[i]]); 129 } else { 130 Modify(1, n, i, x[i]); 131 } 132 } 133 while (m--) { 134 int op, l, r; 135 scanf("%d%d%d", &op, &l, &r); 136 switch (op) { 137 case 0: 138 Cycle(1, n, l, r); 139 Sqr(l, r); 140 break; 141 case 1: 142 printf("%d ", Query(1, n, l, r) + sum.Query(l, r)); 143 break; 144 } 145 } 146 return 0; 147 }