UOJ_14_【UER #1】DZY Loves Graph_并查集
考虑只有前两个操作怎么做。
每次删除一定是从后往前删,并且被删的边如果不是树边则没有影响,如果是树边也不存在边能替代。
直接删除这条边就可以。
于是用一个栈来保存现场,然后按秩合并的并查集维护就OK了。
现在有撤回操作,但根据上面对删边分析出的性质。
可以这样:
如果是插入一条边,然后撤回,相当于删边。
如果删边然后撤回,相当于什么也不做。
代码还是很好理解的。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; typedef long long ll; #define N 500050 inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } int rd() { int x=0; char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc(); return x; } char rc() { char s=nc(); while(s!='A'&&s!='D'&&s!='R'&&s!=EOF) s=nc(); return s; } int fa[N],S[N],top,ec[N],n,m,siz[N]; ll ev[N]; int find(int x) {return fa[x]==x?x:find(fa[x]);} inline void output(int x) {printf("%lld ",ec[x]==n-1?ev[x]:0ll);} void add(int x,int y,int z) { int dx=find(x),dy=find(y); top++; ec[top]=ec[top-1]; ev[top]=ev[top-1]; if(dx==dy) S[top]=0; else { if(siz[dx]>siz[dy]) swap(dx,dy); S[top]=dx; fa[dx]=dy; siz[dy]+=siz[dx]; ec[top]++; ev[top]+=z; } } void del(int K) { while(K--) { int t=S[top--]; siz[fa[t]]-=siz[t]; fa[t]=t; } } int main() { n=rd(); m=rd(); int i,x,y; for(i=1;i<=n;i++) fa[i]=i,siz[i]=1; char s=rc(); for(i=1;i<=m;i++) { if(s=='A') { x=rd(); y=rd(); add(x,y,i); output(top); s=rc(); if(s=='R') del(1); }else if(s=='D') { x=rd(); output(top-x); s=rc(); if(s!='R') del(x); }else { output(top); s=rc(); } } }