bzoj 3674: 可持久化并查集加强版 (启发式合并+主席树)

Description

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

Sample Output

1
0
1
 
思路;
就是bzoj 3673数据范围加大了下。。卡了下其他写法,启发式合并+主席树的写法不会被卡。。
启发式合并也就是按秩合并,把小的并到大的。主席树里多维护一个数组dep,表示集合秩的大小。
又水一道,美滋滋
 
#include<bits/stdc++.h>
using namespace std;
#define mid int m = (l + r) >> 1
const int M = 5e6 + 10;
const int Max = 2e5+10;

int sum[M],ls[M],rs[M],dep[M],n,idx,root[Max];
void build(int l,int r,int &rt){
     rt = ++idx;
    if(l == r){
        sum[rt] = l;
        return ;
    }
    mid;
    build(l,m,ls[rt]); build(m+1,r,rs[rt]);
    return ;
}

void update(int old,int &rt,int p,int c,int l,int r){
    rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old];
    dep[rt] = dep[old];
    if(l == r){
        sum[rt] = c;
        return ;
    }
    mid;
    if(p <= m) update(ls[old],ls[rt],p,c,l,m);
    else update(rs[old],rs[rt],p,c,m+1,r);
}

int query(int p,int l,int r,int rt){
    if(l == r) return rt;
    mid;
    if(p <= m) return query(p,l,m,ls[rt]);
    else return query(p,m+1,r,rs[rt]);
}

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

int fd(int x,int rt){
    int pos = query(x,1,n,rt);
    if(x == sum[pos]) return pos;
    return fd(sum[pos],rt);
}

int main()
{
    int q,op,x,y,k;
    scanf("%d%d",&n,&q);
    build(1,n,root[0]);
    for(int i = 1;i <= q;i ++){
        scanf("%d",&op);
        if(op == 1){
            scanf("%d%d",&x,&y);
            root[i] = root[i-1];
            int fx = fd(x,root[i-1]);
            int fy = fd(y,root[i-1]);
            if(sum[fx] == sum[fy]) continue;
            if(dep[fx] > dep[fy]) swap(fx,fy);
            update(root[i-1],root[i],sum[fx],sum[fy],1,n);
            if(dep[fx] == dep[fy]) add(sum[fy],1,n,root[i]);
        }
        else if(op == 2){
            scanf("%d",&k);
            root[i] = root[k];
        }
        else {
            root[i] = root[i-1];
            scanf("%d%d",&x,&y);
            int fx = fd(x,root[i]);
            int fy = fd(y,root[i]);
            if(sum[fx] == sum[fy]) printf("1\n");
            else printf("0\n");
        }
    }
    return 0;
}

 

 
posted @ 2018-11-06 22:08  冥想选手  阅读(203)  评论(0编辑  收藏  举报