[bzoj] 3673 3674 可持久化并查集 || 可持久化数组

原题

加强版

题意:
可持久化并查集模板……

题解:
用可持久化线段树维护一个可持久化数组,来记录每一次操作后的状态。
不能用路径压缩,但是要按置合并,使复杂度保证在O(log)

#include
#include
#define N 200010
#define M 5000010
using namespace std;
int n,m,f[N],root[N],cnt,sze[M];
struct hhh
{
    int ls,rs,sum;
}tre[M];

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

void change(int &now,int old,int l,int r,int x,int y)
{
    now=++cnt;
    tre[now].rs=tre[old].rs;
    tre[now].ls=tre[old].ls;
    if (l==r) return (void)(tre[now].sum=y);
    int mid=(l+r)>>1;
    if (x>mid) change(tre[now].rs,tre[old].rs,mid+1,r,x,y);
    else change(tre[now].ls,tre[old].ls,l,mid,x,y);
}

void add(int &i,int old,int l,int r,int pos)
{
    i=++cnt;
    tre[i].ls=tre[old].ls;
    tre[i].rs=tre[old].rs;
    if (l==r) return (void)(sze[i]=sze[old]+1);
    int mid=(l+r)>>1;
    if (pos<=mid) add(tre[i].ls,tre[old].ls,l,mid,pos);
    else add(tre[i].rs,tre[old].rs,mid+1,r,pos);
}

int query(int i,int l,int r,int x)
{
    if (!i) return x;
    if (l==r) return tre[i].sum?tre[i].sum:x;
    int mid=(l+r)>>1;
    if (x>mid) return query(tre[i].rs,mid+1,r,x);
    return query(tre[i].ls,l,mid,x);
}

int find(int now,int x)
{
    int fa;
    while (1)
    {
    fa=query(root[now],1,n,x);
    if (x==fa) return x;
    x=fa;
    }
}

int main()
{
    n=read();m=read();
    int a,b,op,x,y;
    for (int i=1;i<=m;i++)
    {
    op=read();a=read();
    if (op==1)
    {
        root[i]=root[i-1];
        b=read();
        x=find(i,a);y=find(i,b);
        if (x==y) continue;
        if (sze[x]>sze[y]) change(root[i],root[i],1,n,y,x);
        else change(root[i],root[i],1,n,x,y);
        if (sze[x]==sze[y]) add(root[i],root[i],1,n,y);
    }
    else if (op==2) root[i]=root[a];
    else root[i]=root[i-1],b=read(),(find(i,a)==find(i,b))?puts("1"):puts("0");
    }
    return 0;
}

你可能感兴趣的:([bzoj] 3673 3674 可持久化并查集 || 可持久化数组)