您的位置:首页 > 其它

BZOJ3674 可持久化并查集加强版

2014-10-04 17:07 387 查看
这是以前做的一道题。

并查集 <=>一个father数组,于是可持久化并查集 <=>可持久化数组。

然后数组如何可持久化呢?用可持久化线段树实现。

每次合并就等价于修改father数组的一个值,就是线段树点修改。

然后查询也是,查father数组中的一个值,就是线段树点查询。

要查询历史版本,就套上可持久化即可。

/**************************************************************
Problem: 3674
User: rausen
Language: C++
Result: Accepted
Time:1496 ms
Memory:158228 kb
****************************************************************/

#include <cstdlib>
#include <cstdio>
#include <algorithm>

using namespace std;

struct segment{
int ls, rs, v, dep;
} seg[10000000];
int tot, last, m, n, root[300000];

void build_seg(int &p, int l, int r){
if (!p) p = ++tot;
if (l == r){
seg[p].v = l;
return;
}
int m = (l + r) >> 1;
build_seg(seg[p].ls, l, m);
build_seg(seg[p].rs, m + 1, r);
}

void modify(int l, int r, int x, int &y, int pos, int val){
y = ++tot;
if (l == r){
seg[y].v = val;
return;
}
seg[y].ls = seg[x].ls;
seg[y].rs = seg[x].rs;
int m = (l + r) >> 1;
if (pos <= m) modify(l, m, seg[x].ls, seg[y].ls, pos, val);
else modify(m + 1, r, seg[x].rs, seg[y].rs, pos, val);
}

void add(int p, int l, int r, int pos){
if (l == r){
++seg[p].dep;
return;
}
int m = (l + r) >> 1;
if (pos <= m) add(seg[p].ls, l, m, pos);
else add(seg[p].rs, m + 1, r, pos);
}

int query(int p, int l, int r, int pos){
if (l == r) return p;
int m = (l + r) >> 1;
if (pos <= m) return query(seg[p].ls, l, m, pos);
else return query(seg[p].rs, m + 1, r, pos);
}

int find(int p, int x){
int k = query(p, 1, n, x);
if (x == seg[k].v) return k;
int t = find(p, seg[k].v);
modify(1, n, p, p, seg[k].v, t);
return t;
}

int main(){
scanf("%d %d\n", &n, &m);
build_seg(root[0], 1, n);
int oper, x, y, p, q;
for(int i = 1; i <= m; ++i){
scanf("%d", &oper);
if (oper == 1){
scanf("%d%d", &x, &y);
x = x ^ last, y = y ^ last;
root[i] = root[i - 1];
p = find(root[i], x), q = find(root[i], y);
if (seg[p].v == seg[q].v) continue;
if (seg[p].dep > seg[q].dep) swap(p, q);
modify(1, n, root[i - 1], root[i], seg[p].v, seg[q].v);
if (seg[p].dep == seg[q].dep) add(root[i], 1, n, seg[q].v);
} else if (oper == 2){
scanf("%d", &x);
x = x ^ last;
root[i] = root[x];
} else{
scanf("%d%d", &x ,&y);
x = x ^ last, y = y ^ last;
root[i] = root[i - 1];
p = find(root[i], x), q = find(root[i], y);
if (seg[p].v == seg[q].v) last = 1; else last = 0;
printf("%d\n", last);
}
}
return 0;
}


View Code
(p.s. 作为一名典型的嘴巴选手,还是要Orz hzwer的程序!!!)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: