zl程序教程

您现在的位置是:首页 >  其它

当前栏目

BZOJ3562 : [SHOI2014]神奇化合物

神奇 化合物
2023-09-11 14:15:05 时间

可以发现,从头到尾有一堆点是始终连在一起的,所以把没被删掉的一开始就有的边都加上后求出每个联通块,

缩完点后我们发现,边数也减少得差不多了,剩下的就直接暴力。

 

#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;
}