BZOJ3674 可持久化并查集加强版

这是以前做的一道题。

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

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

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

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

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

 1 /**************************************************************
 2     Problem: 3674
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:1496 ms
 7     Memory:158228 kb
 8 ****************************************************************/
 9  
10 #include <cstdlib> 
11 #include <cstdio>
12 #include <algorithm>
13  
14 using namespace std;
15  
16 struct segment{
17     int ls, rs, v, dep;
18 } seg[10000000];
19 int tot, last, m, n, root[300000];
20  
21 void build_seg(int &p, int l, int r){
22     if (!p) p = ++tot;
23     if (l == r){
24         seg[p].v = l;
25         return;
26     }
27     int m = (l + r) >> 1;
28     build_seg(seg[p].ls, l, m);
29     build_seg(seg[p].rs, m + 1, r);
30 }
31  
32 void modify(int l, int r, int x, int &y, int pos, int val){
33     y = ++tot;
34     if (l == r){
35         seg[y].v = val;
36         return;
37     }
38     seg[y].ls = seg[x].ls;
39     seg[y].rs = seg[x].rs;
40     int m = (l + r) >> 1;
41     if (pos <= m) modify(l, m, seg[x].ls, seg[y].ls, pos, val);
42     else modify(m + 1, r, seg[x].rs, seg[y].rs, pos, val);
43 }
44  
45 void add(int p, int l, int r, int pos){
46     if (l == r){
47         ++seg[p].dep;
48         return;
49     }
50     int m = (l + r) >> 1;
51     if (pos <= m) add(seg[p].ls, l, m, pos);
52     else add(seg[p].rs, m + 1, r, pos);
53 }
54  
55 int query(int p, int l, int r, int pos){
56     if (l == r) return p;
57     int m = (l + r) >> 1;
58     if (pos <= m) return query(seg[p].ls, l, m, pos);
59     else return query(seg[p].rs, m + 1, r, pos);
60 }
61  
62 int find(int p, int x){
63     int k = query(p, 1, n, x);
64     if (x == seg[k].v) return k;
65     int t = find(p, seg[k].v);
66     modify(1, n, p, p, seg[k].v, t);
67     return t;
68 }
69  
70 int main(){
71     scanf("%d %d
", &n, &m);
72     build_seg(root[0], 1, n);
73     int oper, x, y, p, q;
74     for(int i = 1; i <= m; ++i){
75         scanf("%d", &oper);
76         if (oper == 1){
77             scanf("%d%d", &x, &y);
78             x = x ^ last, y = y ^ last;
79             root[i] = root[i - 1];
80             p = find(root[i], x), q = find(root[i], y);
81             if (seg[p].v == seg[q].v) continue;
82             if (seg[p].dep > seg[q].dep) swap(p, q);
83             modify(1, n, root[i - 1], root[i], seg[p].v, seg[q].v);
84             if (seg[p].dep == seg[q].dep) add(root[i], 1, n, seg[q].v);
85         } else if (oper == 2){
86             scanf("%d", &x);
87             x = x ^ last;
88             root[i] = root[x];
89         } else{
90             scanf("%d%d", &x ,&y);
91             x = x ^ last, y = y ^ last;
92             root[i] = root[i - 1];
93             p = find(root[i], x), q = find(root[i], y);
94             if (seg[p].v == seg[q].v) last = 1; else last = 0;
95             printf("%d
", last);
96         }
97     }
98     return 0;
99 }
View Code

(p.s. 作为一名典型的嘴巴选手,还是要Orz hzwer的程序!!!)

By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
原文地址:https://www.cnblogs.com/rausen/p/4006147.html