UOJ14 UER #1 DZY Loves Graph(最小生成树+并查集)
显然可以用可持久化并查集实现。考虑更简单的做法。如果没有撤销操作,用带撤销并查集暴力模拟即可,复杂度显然可以均摊。加上撤销操作,删除操作的复杂度不再能均摊,但注意到我们在删除时就可以知道他会不会被撤销,所以遇到一个要被撤销的删除操作时,直接求出去掉k条边后的MST即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 300010 #define M 500010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,fa[N],size[N],e[M],cnt,top; char qwerty[10]; ll ans; struct data{int op,x,y; }q[M]; struct data2{int x,fa,s,i;ll sum; }stk[N<<1]; int find(int x){return fa[x]==x?x:find(fa[x]);} int merge(int x,int y,int i) { x=find(x),y=find(y); if (x==y) return 0; if (size[x]<size[y]) swap(x,y); top++;stk[top].x=x;stk[top].fa=fa[x];stk[top].s=size[x];stk[top].i=i;stk[top].sum=stk[top-1].sum+i; top++;stk[top].x=y;stk[top].fa=fa[y];stk[top].s=size[y];stk[top].i=i;stk[top].sum=stk[top-1].sum+i; size[x]+=size[y],fa[y]=x; return i; } int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=m;i++) { char c=getc(); if (c=='A') q[i].op=0,q[i].x=read(),q[i].y=read(); if (c=='D') q[i].op=1,q[i].x=read(); if (c=='R') q[i].op=2,cin>>qwerty; } for (int i=1;i<=n;i++) fa[i]=i,size[i]=1; for (int i=1;i<=m;i++) { if (q[i].op==0) ans+=merge(q[i].x,q[i].y,i),e[++cnt]=i; if (q[i].op==1) { int l=1,r=top,u=0; while (l<=r) { int mid=l+r>>1; if (stk[mid].i<=e[cnt-q[i].x]) u=mid,l=mid+1; else r=mid-1; } ans=stk[u].sum>>1; if (q[i+1].op!=2) { cnt-=q[i].x; while (stk[top].i>e[cnt]) fa[stk[top].x]=stk[top].fa,size[stk[top].x]=stk[top].s,top--; } } if (q[i].op==2) { if (q[i-1].op==0) { int x=0; while (stk[top].i==i-1) fa[stk[top].x]=stk[top].fa,size[stk[top].x]=stk[top].s,x+=stk[top].i,top--; ans-=x>>1;cnt--; } else ans=stk[top].sum/2; } if (top==(n-1<<1)&&ans==stk[top].sum/2) printf(LL,ans); else printf("0\n"); //for (int j=1;j<=cnt;j++) cout<<e[j]<<' ';cout<<endl; //for (int j=2;j<=top;j+=2) cout<<stk[j].i<<' '<<stk[j].sum/2<<endl; //cout<<endl; } return 0; }