由于加入的边权递增,可以直接运行kruskal并支持撤销,但这样如果反复批量删边和撤销,时间复杂度会退化,因此需要对删边操作加上延时处理,只有在删边后下一个操作不是撤销时才执行删边。由于有撤销,并查集需要按秩合并且不路径压缩。
#include<bits/stdc++.h> typedef long long i64; const int N=500007; int _(){ int x; scanf("%d",&x); return x; } int n,m; int f[N][2]; int po,ep=0,ep1=0; #define sz f][1 #define fa f][0 int gf(int x){ while(x!=x[fa])x=x[fa]; return x; } void lk(int x,int y){ x[fa]=y; y[sz]+=x[sz]; } void ct(int x,int y){ x[fa]=x; y[sz]-=x[sz]; } struct ev{ int a,b,ec; i64 sum; void undo(){ct(a,b);} }e[N]; void fix(){ while(ep1<ep)e[ep--].undo(); } void ae(int v){ po=0; fix(); ev&e0=e[ep]; ev&e1=e[ep1=++ep]; int x=gf(_()),y=gf(_()); if(x==y){ e1=(ev){0,0,e0.ec,e0.sum}; }else{ if(x[sz]>y[sz])std::swap(x,y); lk(x,y); e1=(ev){x,y,e0.ec+1,e0.sum+v}; } } void de(){ po=1; fix(); ep1=ep-_(); } void undo(){ if(!po)e[ep--].undo(); ep1=ep; } int main(){ n=_();m=_(); for(int i=1;i<=n;++i){ i[fa]=i; i[sz]=1; } for(int i=1,o;i<=m;++i){ o=_(); if(o==2272)ae(i); else if(o==2596033)de(); else undo(); printf("%lld",e[ep1].ec==n-1?e[ep1].sum:0); } return 0; }