BZOJ3562 : [SHOI2014]神奇化合物
可以发现,从头到尾有一堆点是始终连在一起的,所以把没被删掉的一开始就有的边都加上后求出每个联通块,
缩完点后我们发现,边数也减少得差不多了,剩下的就直接暴力。
#include<cstdio> #define N 5010 #define M 200010 #define Q 10010 inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} struct opration{int k,i,j;}op[Q]; int n,m,q,i,u[M],v[M],f[N],id[N],tot,g[N],from[N],ed,w[M],nxt[M],ans,time,e[N][N]; bool del[N][N],have[N][N]; char c; int F(int x){return f[x]==x?x:f[x]=F(f[x]);} inline void addedge(int x,int y){w[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x,int y){ from[x]=y; for(int i=g[x];i;i=nxt[i])if(e[x][w[i]]&&from[w[i]]!=y)dfs(w[i],y); } inline void add(int x,int y){ if(from[x]!=from[y]){ ans--; dfs(y,from[x]); } e[x][y]++;e[y][x]++; if(!have[x][y])addedge(x,y),addedge(y,x),have[x][y]=have[y][x]=1; } inline void deled(int x,int y){ e[x][y]--;e[y][x]--; dfs(x,++time); if(from[y]!=from[x])ans++; } int main(){ for(read(n),read(m),i=1;i<=m;i++)read(u[i]),read(v[i]); for(read(q),i=1;i<=q;i++){ while(!(((c=getchar())=='A')||(c=='D')||(c=='Q'))); if(c=='A')read(op[i].i),read(op[i].j); if(c=='D')op[i].k=1,read(op[i].i),read(op[i].j),del[op[i].i][op[i].j]=del[op[i].j][op[i].i]=1; if(c=='Q')op[i].k=2; } for(i=1;i<=n;i++)f[i]=i; for(i=1;i<=m;i++)if(!del[u[i]][v[i]]&&F(u[i])!=F(v[i]))f[f[u[i]]]=f[v[i]]; for(i=1;i<=n;i++)f[i]=F(i); for(i=1;i<=n;i++){ if(!id[f[i]])id[f[i]]=++tot; f[i]=id[f[i]]; } ans=time=tot; for(i=1;i<=tot;i++)from[i]=i; for(i=1;i<=m;i++)if(f[u[i]]!=f[v[i]])add(f[u[i]],f[v[i]]); for(i=1;i<=q;i++){ op[i].i=f[op[i].i],op[i].j=f[op[i].j]; if(op[i].k==0&&op[i].i!=op[i].j)add(op[i].i,op[i].j); if(op[i].k==1&&op[i].i!=op[i].j)deled(op[i].i,op[i].j); if(op[i].k==2)printf("%d\n",ans); } return 0; }