1. 程式人生 > >BZOJ3674:可持久化並查集加強版

BZOJ3674:可持久化並查集加強版

淺談主席樹:https://www.cnblogs.com/AKMer/p/9956734.html

題目傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=3674

因為要支援歷史操作,所以我們用可持久化線段樹來維護並查集的祖先陣列。

因為要路徑壓縮,所以每個點會被建\(k*logn\)次,\(k\)未知,但是絕對不大。

時間複雜度:\(O(mklogn)\)

空間複雜度:\(O(mklogn)\)

程式碼如下:

#include <cstdio>
using namespace std;

const int maxn=2e5+5;

int rt[maxn];
int n,m,lstans;

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

struct tree_node {
    int fa,ls,rs;
};

struct Chairman_tree {
    int tot;
    tree_node tree[maxn*40];

    void build(int &now,int l,int r) {
        now=++tot;
        if(l==r) {tree[now].fa=l;return;}
        int mid=(l+r)>>1;
        build(tree[now].ls,l,mid);
        build(tree[now].rs,mid+1,r);
    }

    int query(int now,int l,int r,int pos) {
        if(l==r)return tree[now].fa;
        int mid=(l+r)>>1;
        if(pos<=mid)return query(tree[now].ls,l,mid,pos);
        return query(tree[now].rs,mid+1,r,pos);
    }

    void change(int lst,int &now,int l,int r,int pos,int v) {
        now=++tot;tree[now]=tree[lst];
        if(l==r) {tree[now].fa=v;return;}
        int mid=(l+r)>>1;
        if(pos<=mid)change(tree[lst].ls,tree[now].ls,l,mid,pos,v);
        else change(tree[lst].rs,tree[now].rs,mid+1,r,pos,v);
    }
}T;

int find(int &root,int x) {
    int f=T.query(root,1,n,x);
    if(f==x)return x;
    int res=find(root,f);
    T.change(root,root,1,n,x,res);//路徑壓縮相當於在上一版本主席樹上面更改祖先陣列
    return res;
}

int main() {
    n=read(),m=read();
    T.build(rt[0],1,n);
    for(int i=1;i<=m;i++) {
        int opt=read();
        if(opt==1) {
            int a=read()^lstans,b=read()^lstans;
            int p=find(rt[i-1],a),q=find(rt[i-1],b);
            if(p==q)rt[i]=rt[i-1];//如果不需要合併就不合並
            else T.change(rt[i-1],rt[i],1,n,p,q);
        }
        else if(opt==2) {
            int t=read()^lstans;
            rt[i]=rt[t];
        }
        else if(opt==3) {
            int a=read()^lstans,b=read()^lstans;
            int p=find(rt[i-1],a),q=find(rt[i-1],b);
            if(p==q)lstans=1;
            else lstans=0;
            rt[i]=rt[i-1];//詢問也算操作
            printf("%d\n",lstans);
        }
    }
    return 0;
}