4105: [Thu Summer Camp 2015]平方运算

首先嘛这道题目只要知道一个东西就很容易了:所有循环的最小公约数<=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\n", Query(1, n, l, r) + sum.Query(l, r));
143         break;
144     }
145   }
146   return 0;
147 }

 

posted @ 2015-06-18 21:05  New_Godess  阅读(177)  评论(0编辑  收藏