BZOJ-3673/3674:可持久化并查集

[文章目录]

Descritption

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

可持久化线段树维护可持久化数组,进而维护按秩合并的并查集。
合并的时候,每次查询一次fa[x]时间logn,查询log次,按秩合并后修改辅助度logn。总时间复杂度O(nlog^2n)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
struct seg
{
    int ls,rs,w,siz;
}t[13000000];
int rot[201000],se;
int build(int l,int r)
{
    int re=++se;
    if(l==r)
    {
        t[re].w=l; t[re].siz=1;
        return re;
    }
    int mid=(l+r)>>1;
    t[re].ls=build(l,mid);
    t[re].rs=build(mid+1,r);
    return re;
}
void insert(int &p1,int p2,int l,int r,int x,int y,int z)
{
    p1=++se;
    if(l==r) {t[p1].w=y; t[p1].siz=z; return;}
    int mid=(l+r)>>1;
    if(x<=mid) t[p1].rs=t[p2].rs,insert(t[p1].ls,t[p2].ls,l,mid,x,y,z);
    else t[p1].ls=t[p2].ls,insert(t[p1].rs,t[p2].rs,mid+1,r,x,y,z);
}
int query(int p,int l,int r,int x)
{
    if(l==r) return p;
    int mid=(l+r)>>1;
    if(x<=mid) return query(t[p].ls,l,mid,x);
    else return query(t[p].rs,mid+1,r,x);
}
int main()
{
    scanf("%d%d",&n,&m);
    rot[0]=build(1,n);
    int x,y,sw,now=0,k,p,ans=0;
    while(m--)
    {
        scanf("%d",&sw);
        ++now; rot[now]=rot[now-1];
        if(sw==1)
        {
            scanf("%d%d",&x,&y); x^=ans; y^=ans;
            p=query(rot[now],1,n,x);
            while(x!=t[p].w) x=t[p].w,p=query(rot[now],1,n,x);
            x=p;
            p=query(rot[now],1,n,y);
            while(y!=t[p].w) y=t[p].w,p=query(rot[now],1,n,y);
            y=p;
            if(x!=y)
            {
                if(t[x].siz>t[y].siz) swap(x,y);
                insert(rot[now],rot[now],1,n,t[y].w,t[y].w,t[x].siz+t[y].siz);
                insert(rot[now],rot[now],1,n,t[x].w,t[y].w,0);
            }
        }
        else if(sw==2) {scanf("%d",&k); k^=ans; rot[now]=rot[k];}
        else
        {
            scanf("%d%d",&x,&y); x^=ans; y^=ans;
            p=query(rot[now],1,n,x);
            while(x!=t[p].w) x=t[p].w,p=query(rot[now],1,n,x);
            p=query(rot[now],1,n,y);
            while(y!=t[p].w) y=t[p].w,p=query(rot[now],1,n,y);
            if(x==y) ans=1,puts("1");
            else ans=0,puts("0");
        }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注