1. 程式人生 > >[bzoj] 3673 3674 可持久化並查集 || 可持久化數組

[bzoj] 3673 3674 可持久化並查集 || 可持久化數組

www. getchar 可持久化線段樹 for puts == markdown efi query

原題

加強版

題意:
可持久化並查集模板……

題解:
用可持久化線段樹維護一個可持久化數組,來記錄每一次操作後的狀態。
不能用路徑壓縮,但是要按置合並,使復雜度保證在O(log)

#include<cstdio>
#include<algorithm>
#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 可持久化並查集 || 可持久化數組