您的位置:首页 > 其它

可持久性数组 bzoj3674 可持久化并查集加强版

2016-01-03 19:38 357 查看
传送门:点击打开链接

题意: 强制在线操作,定义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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: