可以发现,从头到尾有一堆点是始终连在一起的,所以把没被删掉的一开始就有的边都加上后求出每个联通块,
缩完点后我们发现,边数也减少得差不多了,剩下的就直接暴力。
#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
",ans);
}
return 0;
}