bzoj3674: 可持久化并查集加强版
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
Input
Output
Sample Input
5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2
Sample Output
1
0
1
0
1
这里用到了主席树的一个性质:支持历史版本的操作,我们用主席树在每个点上表示它的祖先,感觉有点浪费,反正瞎搞就过了
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; int bh, n, tn, m, l, r, G, a, b, cases; int root[200010]; int Hash[200010]; struct NODe{ int lson, rson, val; }tree[200010 * 100]; void build(int &u,int l, int r) { u=bh++; if(l==r) { tree[u].val=0; return; } int mid=(l+r)>>1; build(tree[u].lson,l,mid); build(tree[u].rson,mid+1,r); } /*int update(int i, int l, int r, int old, int val) { if (l == r) { bh++; tree[bh].val = val; return bh; } int tbh; int mid = (l + r) >> 1; if (i > mid) { bh++; tbh = bh; tree[bh].lson = tree[old].lson; tree[tbh].rson = update(i, mid + 1, r, tree[old].rson, val); } else { bh++; tbh = bh; tree[bh].rson = tree[old].rson; tree[tbh].lson = update(i, l, mid, tree[old].lson, val); } // printf("%d %d %d %d", i, l, r, old); // printf(" change->%d\n", tbh); // printf("lson=%d rson=%d\n", tree[tbh].lson, tree[tbh].rson); return tbh; }*/ void update(int l,int r,int &x,int y,int pos,int val) { if(l==r) { x=bh++; tree[x].val=val; return; } int mid=(l+r)>>1; if(pos>mid) { x=bh++; tree[x].lson=tree[y].lson; update(mid+1,r,tree[x].rson,tree[y].rson,pos,val); }else { x=bh++; tree[x].rson=tree[y].rson; update(l,mid,tree[x].lson,tree[y].lson,pos,val); } } int query(int rt, int wz, int l, int r) { if(l == r){ return tree[rt].val; } int mid = (l + r) / 2; if (wz <= mid) { return query(tree[rt].lson, wz, l, mid); }else{ return query(tree[rt].rson, wz, mid + 1, r); } } int get_father(int rt,int x,int i) { int tmp=query(rt,x,1,n); if (tmp==0) return x; int fa=get_father(rt,tmp,i); update(1,n,root[i],root[i],x,fa); return fa; } int main() { scanf("%d%d", &n, &m); build(root[0],1,n); int lastans = 0; for (int i = 1; i <= m; i++) { scanf("%d", &cases); if (cases == 1) { scanf("%d%d", &a, &b); a = a ^ lastans; b = b ^ lastans; root[i] = root[i - 1]; int fax = get_father(root[i], a, i); int fay = get_father(root[i], b, i); if (fax != fay) { update(1, n,root[i], root[i],fax, fay); } } else if (cases == 2) { scanf("%d", &a); a = a ^ lastans; root[i] = root[a]; } else { scanf("%d%d", &a, &b); a = a ^ lastans; b = b ^ lastans; root[i] = root[i - 1]; int fax = get_father(root[i], a, i); int fay = get_father(root[i], b, i); // printf("%d %d %d %d\n", a, fax, b, fay); if (fax == fay) { lastans = 1; } else { lastans = 0; } printf("%d\n", lastans); } } //system("pause"); return 0; }
个人觉得我的代码比hgz的精简吧
此题还能用rope瞎搞
#include<iostream> #include<cstdio> #include<algorithm> #include<ext/rope> using namespace std; using namespace __gnu_cxx; #define maxn 200010 rope<int> *rp[maxn]; int a[maxn]; int findrep(int i,int x) { if(rp[i]->at(x)==x) return x; int f=findrep(i,rp[i]->at(x)); if (f==rp[i]->at(x)) return f; rp[i]->replace(x,f); return f; } int main() { int n,m; scanf("%d %d",&n,&m); int x,y,lastans=0,Mode; for(int i=1;i<=n;i++) a[i]=i; rp[0]=new rope<int> (a,a+n+1); for(int i=1;i<=m;i++) { rp[i]=new rope<int> (*rp[i-1]); scanf("%d",&Mode); if(Mode==1) { scanf("%d %d",&x,&y); x^=lastans; y^=lastans; int fx=findrep(i,x),fy=findrep(i,y); if(fx!=fy) { rp[i]->replace(fy,fx); } }else if(Mode==2) { scanf("%d",&x); x^=lastans; rp[i]=rp[x]; }else { int a,b; scanf("%d %d",&a,&b); a^=lastans,b^=lastans; printf("%d\n",lastans=(findrep(i,a)==findrep(i,b))); } } return 0; }