4105: [Thu Summer Camp 2015]平方运算
2015-06-18 21:05
495 查看
首先嘛这道题目只要知道一个东西就很容易了:所有循环的最小公约数<=60,成一条链的长度最大为11,那么我们就可以用一个很裸的方法。对于在链上的数,我们修改直接暴力找出并修改。对于在环上的数,我们对每一步建立一颗线段树,那么修改就变成了交换60棵线段树的某个子树。然后我们就可以愉快的写啦~~~
在想的时候被同学坑了,他说最长的循环不超过60.。。。
在实现方面,我用一个map+树状数组维护链上的答案,然后用60棵线段树来维护这个环。懂了之后还是很好写哒~~~
Code:
在想的时候被同学坑了,他说最长的循环不超过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; }
相关文章推荐
- 返回二维数组最大子数组的和(2)
- Redis 2.8 配置文件说明
- TC Srm524 Div 1 T3
- Dynamic Programming | Set 2 (Optimal Substructure Property)
- 总结应用发布
- Android基于TrafficStats实现实时流量统计
- Linux 如何新增驱动模块
- HMM/MEMM/CRF
- 架构师速成4-幼儿园
- 我的Hook学习笔记
- 杭电1010(WA)
- 架构师速成4-幼儿园 分类: 架构师速成 2015-06-18 21:03 529人阅读 评论(0) 收藏
- Canvas元素基本知识
- 安装OpenCV:OpenCV 3.0、OpenCV 2.4.8、OpenCV 2.4.9 +VS 开发环境配置
- CodeForces 360A - Levko and Array Recovery (思维)
- ThinkPad T440换装固态硬盘(SSD)和内存条
- Structual设计--Flyweight模式
- 如何用Linux外接显示器或投影仪
- [转]hive metadata 存mysql 注释中文乱码的有关
- Scroller中的startScroll方法