[题解]lgP5214
思路:由于操作数很小,所以其实大部分的点是不会被修改的,所以预处理出那些永远不会被修改的点,放到并查集里,接着就可以暴力了.
#include<bits/stdc++.h>
using namespace std;
int exist[5010][5010],x[1000010],y[1000010],n,q,m;
bool vis[5010];
char ch[1000010];
int fa[1000010],l[1000010],r[1000010];
struct node{
int next,to;
}e[1000010 * 2];
int tot,fir[1000010];
void add(int x,int to){
e[++tot].to=to;
e[tot].next=fir[x];
fir[x]=tot;
}
void dfs(int x){
vis[x] = 1;
for (int i = fir[x];i;i = e[i].next)
if (!vis[e[i].to] && exist[x][e[i].to])
dfs(e[i].to);
}
int get(int k){
if(fa[k] == k)return k;
return fa[k] = get(fa[k]);
}
int main(){
cin>>n>>m;
for(int i = 1;i <= m;i++){
cin>>x[i]>>y[i];
exist[x[i]][y[i]] = exist[y[i]][x[i]] = 1;
}
for(int i = 1;i <= n;i++)fa[i]=i;
cin>>q;
for(int i = 1;i <= q;i++){
cin>>ch[i];
if(ch[i] != 'Q'){
cin>>l[i]>>r[i];
}
if(ch[i] == 'D')
exist[l[i]][r[i]] = exist[r[i]][l[i]] = 0;
}//不在这里处理ch[i]==A的情况因为这会影响到后面的询问,就是Q1早于某一条连边,但是这条连边由于没有被断开,所以Q1的查询其实是错误的
//但是可以处理ch[i]==D的情况,因为我们要找的是从来没被修改过的边,而需要修改的可以暴力
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
if(exist[i][j])
fa[get(i)]=get(j);
memset(exist,0,sizeof(exist));
for(int i = 1;i <= m;i++){//将原有的边(缩完点之后)相连
if(!exist[get(x[i])][get(y[i])]){
add(get(x[i]),get(y[i]));
add(get(y[i]),get(x[i]));
}
exist[get(x[i])][get(y[i])]++;
exist[get(y[i])][get(x[i])]++;
}
for(int i = 1;i <= q;i++){
if (ch[i]=='Q'){//暴力找联通块
memset(vis,0,sizeof(vis));
int ans=0;
for(int i = 1;i <= n;i++)
if(!vis[get(i)])
dfs(get(i)),ans++;
printf("%d\n",ans);
}
if(ch[i] == 'D'){
exist[get(l[i])][get(r[i])] = max(0,exist[get(l[i])][get(r[i])] - 1);
exist[get(r[i])][get(l[i])] = exist[get(l[i])][get(r[i])];
}
if(ch[i] == 'A'){
if(!exist[get(l[i])][get(r[i])])//没被加入就加边
add(get(l[i]),get(r[i])),add(get(r[i]),get(l[i]));
exist[get(l[i])][get(r[i])]++;
exist[get(r[i])][get(l[i])]++;
}
}
return 0;
}