可持久性数组 bzoj3674 可持久化并查集加强版
2016-01-03 19:38
357 查看
传送门:点击打开链接
题意: 强制在线操作,定义3种操作,查询两个点是否在同一集合,合并两个点,把状态恢复到之前的某个状态
思路:利用线段树实现的可持久性数组,其实原理上就是线段树,那么是如何实现可持久性数组的呢。
对于某次修改,就再造一颗线段树,但是这样明显效率和空间都会爆炸。
因为我们其实有很多节点都是上一次剩下的,其实我只需要新建新添加的那条链上的节点即可。其他节点只需要直接接在以前的上面就行了。
然后我们如果能实现持久性数组,那么就能实现持久性并查集,持久性链表,持久性线段树,持久性平衡树等等!
对于并查集,就算不压缩路径,只是按照深度去启发式合并,效率也能保持在O(logn)以内的
然后就能搞这道题了
题意: 强制在线操作,定义3种操作,查询两个点是否在同一集合,合并两个点,把状态恢复到之前的某个状态
思路:利用线段树实现的可持久性数组,其实原理上就是线段树,那么是如何实现可持久性数组的呢。
对于某次修改,就再造一颗线段树,但是这样明显效率和空间都会爆炸。
因为我们其实有很多节点都是上一次剩下的,其实我只需要新建新添加的那条链上的节点即可。其他节点只需要直接接在以前的上面就行了。
然后我们如果能实现持久性数组,那么就能实现持久性并查集,持久性链表,持久性线段树,持久性平衡树等等!
对于并查集,就算不压缩路径,只是按照深度去启发式合并,效率也能保持在O(logn)以内的
然后就能搞这道题了
#include<map> #include<set> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<string> #include<vector> #include<cstring> #include<iomanip> #include<iostream> #include<algorithm> #include<functional> #define fuck(x) cout<<"["<<x<<"]" #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w+",stdout) using namespace std; typedef long long LL; typedef pair<int, int>PII; const int MX = 5e6 + 5; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; int deep[MX], n, m; int o[MX], ls[MX], rs[MX], s[MX], sz; void build(int l, int r, int &rt) { rt = ++sz; if(l == r) { s[rt] = l; deep[rt] = 0; return; } int m = (l + r) >> 1; build(l, m, ls[rt]); build(m + 1, r, rs[rt]); } int query(int pos, int l, int r, int rt) { if(l == r) return rt; int m = (l + r) >> 1; if(pos <= m) return query(pos, l, m, ls[rt]); return query(pos, m + 1, r, rs[rt]); } void add(int pos, int val, int l, int r, int pr, int &rt) { rt = ++sz; if(l == r) {s[rt] = val; deep[rt] = deep[pr]; return;} ls[rt] = ls[pr]; rs[rt] = rs[pr]; int m = (l + r) >> 1; if(pos <= m) add(pos, val, l, m, ls[pr], ls[rt]); else add(pos, val, m + 1, r, rs[pr], rs[rt]); } void update(int pos, int l, int r, int pr, int &rt) { rt == ++sz; if(l == r) {s[rt] = s[pr]; deep[rt] = deep[pr] + 1 ; return;} ls[rt] = ls[pr]; rs[rt] = rs[pr]; int m = (l + r) >> 1; if(pos <= m) update(pos, l, m, ls[pr], ls[rt]); else update(pos, m + 1, r, rs[pr], rs[rt]); } int find(int x, int rt) { int p = query(x, 1, n, rt); if(s[p] == x) return p; return find(s[p], rt); } inline int read() { char c = getchar(); while(!isdigit(c)) c = getchar(); int x = 0; while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x; } int main() { //FIN; while(~scanf("%d%d", &n, &m)) { sz = 0; build(1, n, o[0]); int last = 0; for(int i = 1; i <= m; i++) { int op, a, b; o[i] = o[i - 1]; op = read(); a = read(); a ^= last; if(op == 1) { b = read(); b ^= last; a = find(a, o[i]), b = find(b, o[i]); if(s[a] == s[b]) continue; if(deep[a] > deep[b]) swap(a, b); add(s[a], s[b], 1, n, o[i - 1], o[i]); if(deep[a] == deep[b]) update(s[b], 1, n, o[i], o[i]); } else if(op == 2) o[i] = o[a]; else { b = read(); b ^= last; a = find(a, o[i]), b = find(b, o[i]); last = (a == b); printf("%d\n", last); } } } return 0; }
相关文章推荐
- C++ 中 stack和queue使用方法
- 交错数组(C# 编程指南)
- 那些可以整除的数字
- 工作流学习(一)——初始工作流
- Python两种列表翻转方法的效率比较
- Li Fei-fei写给她学生的一封信,如何做好研究以及写好PAPER
- MFC之TCP简单客户端实现
- systemback-----做你折腾的后盾
- iOS UI-UIScrollView控件实现图片缩放功能
- 中国知网天津工业大学
- jstorm安装配置
- poj-1321(简单搜索)
- lvs-nat&lvs-dr&FWM&持久连接
- redis安装
- leetcode@ [34] Search for a Range (STL Binary Search)
- ubuntu12.04用NAT方式通过windows上网
- poj 2823(单调队列)
- Java — 多线程
- 多维数组(C# 编程指南)
- 稀疏模型与结构性稀疏模型