[题解]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;
}

参考题解

posted @ 2020-10-20 08:20  czyczy  阅读(97)  评论(0编辑  收藏  举报