您的位置:首页 > 其它

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

2015-06-18 21:05 495 查看
首先嘛这道题目只要知道一个东西就很容易了:所有循环的最小公约数<=60,成一条链的长度最大为11,那么我们就可以用一个很裸的方法。对于在链上的数,我们修改直接暴力找出并修改。对于在环上的数,我们对每一步建立一颗线段树,那么修改就变成了交换60棵线段树的某个子树。然后我们就可以愉快的写啦~~~

在想的时候被同学坑了,他说最长的循环不超过60.。。。

在实现方面,我用一个map+树状数组维护链上的答案,然后用60棵线段树来维护这个环。懂了之后还是很好写哒~~~

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 100000 + 10, kCycle = 60 + 10;

int n, m, p, x
;

int dist
, cycle = 1;

inline int GCD(int a, int b) { return b ? GCD(b, a % b) : a; }
inline int LCM(int a, int b) { return a * b / GCD(a, b); }

int pre
;

void Analysis(int a) {
dist[a] = -2;
int b = a * a % p;
if (dist[b] == -1) {
pre[b] = a;
Analysis(b);
} else if (dist[b] == -2) {
int cnt = 1;
for (int i = a; i != b; i = pre[i], ++cnt) dist[i] = 0;
dist[b] = 0;
cycle = LCM(cycle, cnt);
}
if (dist[a] == -2) dist[a] = dist[b] + 1;
}

inline int pos(int l, int r) { return (l + r) | (l != r); }

int tree[N * 2][kCycle], shift[N * 2];

inline void Merge(int u[], int a[], int b[]) {
for (int i = 0; i < cycle; ++i) u[i] = a[i] + b[i];
}

inline void Shift(int id, int v) {
static int temp[kCycle * 2];
(shift[id] += v) %= cycle;
for (int i = 0; i < cycle; ++i) temp[i] = tree[id][(i + v) % cycle];
std::copy(temp, temp + cycle, tree[id]);
}

void Modify(int l, int r, int u, int v) {
int id = pos(l, r);
for (int i = 0; i < cycle; ++i, (v *= v) %= p) tree[id][i] += v;
if (l == r) return;
int mid = (l + r) / 2;
if (shift[id]) {
Shift(pos(l, mid), shift[id]);
Shift(pos(mid + 1, r), shift[id]);
shift[id] = 0;
}
if (u <= mid) Modify(l, mid, u, v); else Modify(mid + 1, r, u, v);
}

void Cycle(int l, int r, int u, int v) {
int id = pos(l, r);
if (u <= l && r <= v) {
Shift(id, 1);
return;
}
int mid = (l + r) / 2;
if (shift[id]) {
Shift(pos(l, mid), shift[id]);
Shift(pos(mid + 1, r), shift[id]);
shift[id] = 0;
}
if (u <= mid) Cycle(l, mid, u, v);
if (v > mid) Cycle(mid + 1, r, u, v);
Merge(tree[id], tree[pos(l, mid)], tree[pos(mid + 1, r)]);
}

int Query(int l, int r, int u, int v) {
int id = pos(l, r);
if (u <= l && r <= v) return tree[id][0];
int mid = (l + r) / 2, res = 0;
if (shift[id]) {
Shift(pos(l, mid), shift[id]);
Shift(pos(mid + 1, r), shift[id]);
shift[id] = 0;
}
if (u <= mid) res += Query(l, mid, u, v);
if (v > mid) res += Query(mid + 1, r, u, v);
return res;
}

class BIT {
int data
;

public:
inline void Add(int p, int v) { for (; p <= n; p += p & -p) data[p] += v; }
inline int Query(int p) {
int res = 0;
for (; p; p ^= p & -p) res += data[p];
return res;
}
inline int Query(int l, int r) { return Query(r) - Query(l - 1); }

} cnt, sum;

void Sqr(int l, int r) {
if (!cnt.Query(l, r)) return;
if (l == r) {
cnt.Add(l, -1);
sum.Add(l, -x[l]);
if (cnt.Query(l, l) == 0)
Modify(1, n, l, (x[l] *= x[l]) %= p);
else
sum.Add(l, (x[l] *= x[l]) %= p);
} else {
int mid = (l + r) / 2;
Sqr(l, mid);
Sqr(mid + 1, r);
}
}

int main() {
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; ++i) scanf("%d", x + i);
memset(dist, -1, sizeof dist);
for (int i = 0; i < p; ++i) if (dist[i] == -1) Analysis(i);
for (int i = 1; i <= n; ++i) {
if (dist[x[i]]) {
sum.Add(i, x[i]);
cnt.Add(i, dist[x[i]]);
} else {
Modify(1, n, i, x[i]);
}
}
while (m--) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
switch (op) {
case 0:
Cycle(1, n, l, r);
Sqr(l, r);
break;
case 1:
printf("%d\n", Query(1, n, l, r) + sum.Query(l, r));
break;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: