[BZOJ 3674]可持久化并查集加强版

Description

自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就可以轻松虐!
zky:……

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
0<n,m<=2*10^5

Sample Input

5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2

Sample Output

1
0
1

题解

用启发式合并的话,我们发现对历史并查集只需要将深度小的根节点的父亲修改就可以了。

那么可持久化数组单点修改就ojbk了。可持久化数组用主席树实现。

  1 //It is made by Awson on 2017.10.5
  2 #include <map>
  3 #include <set>
  4 #include <cmath>
  5 #include <ctime>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <string>
 11 #include <cstdlib>
 12 #include <cstring>
 13 #include <iostream>
 14 #include <algorithm>
 15 #define LL long long
 16 #define Max(a, b) ((a) > (b) ? (a) : (b))
 17 #define Min(a, b) ((a) < (b) ? (a) : (b))
 18 #define sqr(x) ((x)*(x))
 19 using namespace std;
 20 const int N = 2e5;
 21 void read(int &x) {
 22   char ch; bool flag = 0;
 23   for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
 24   for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
 25   x *= 1-2*flag;
 26 }
 27 
 28 struct node {
 29   int key;
 30   node *child[2];
 31 }sgm[N*30+5], *pos = sgm;
 32 node* root[N+5];
 33 int dep[N+5];
 34 int n, m, lastans;
 35 int opt, a, b;
 36 
 37 void build(node* &o, int l, int r) {
 38   if (l == r) {
 39     dep[l] = 1;
 40     return;
 41   }
 42   int mid = (l+r)>>1;
 43   o->child[0] = ++pos, build(o->child[0], l, mid);
 44   o->child[1] = ++pos, build(o->child[1], mid+1, r);
 45 }
 46 void update(node* &o, int l, int r, int loc, int val) {
 47   node* t = o;
 48   o = ++pos;
 49   if (l == r) {
 50     o->key = val;
 51     return;
 52   } else {
 53     o->child[0] = t->child[0];
 54     o->child[1] = t->child[1];
 55   }
 56   int mid = (l+r)>>1;
 57   if (loc <= mid) update(o->child[0], l, mid, loc, val);
 58   else update(o->child[1], mid+1, r, loc, val);
 59 }
 60 int query(node *o, int l, int r, int loc) {
 61   if (l == r) return o->key;
 62   int mid = (l+r)>>1;
 63   if (loc <= mid) return query(o->child[0], l, mid, loc);
 64   else return query(o->child[1], mid+1, r, loc);
 65 }
 66 int find(node *o, int loc) {
 67   while (true) {
 68     int tmp = query(o, 1, n, loc);
 69     if (!tmp) return loc;
 70     loc = tmp;
 71   }
 72 }
 73 void work() {
 74   read(n), read(m);
 75   root[0] = pos;
 76   build(root[0], 1, n);
 77   for (int i = 1; i <= m; i++) {
 78     read(opt);
 79     if (opt == 1) {
 80       root[i] = root[i-1];
 81       read(a), read(b);
 82       a ^= lastans, b ^= lastans;
 83       int p = find(root[i], a);
 84       int q = find(root[i], b);
 85       if (p != q) {
 86     if (dep[p] == dep[q]) dep[p]++;
 87     else if (dep[p] < dep[q]) swap(p, q);
 88     update(root[i], 1, n, q, p);
 89       }
 90     }
 91     else if (opt == 2) read(a), a ^= lastans, root[i] = root[a];
 92     else {
 93       read(a), read(b);
 94       a ^= lastans, b ^= lastans;
 95       root[i] = root[i-1];
 96       int p = find(root[i], a);
 97       int q = find(root[i], b);
 98       if (p != q) printf("0\n"), lastans = 0;
 99       else printf("1\n"), lastans = 1;
100     }
101   }
102 }
103 int main() {
104   work();
105   return 0;
106 }

 

posted @ 2017-10-05 10:31  NaVi_Awson  阅读(209)  评论(0编辑  收藏  举报