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;

}

  

 

你可能感兴趣的:(ZOJ)