2020牛客暑期多校训练营(第三场)G题Operating on a Graph(并查集与链表)

2020牛客暑期多校训练营(第三场)G题Operating on a Graph(并查集与链表)

Operating on a Graph

题意:给一个图,q次操作,输入一个颜色op,若无op颜色则不管,否则将op相邻的颜色改为op,输出最后每个点的颜色,最开始每个点的颜色等于本身的点。

题解:并查集比较简单,主要是不用链表或按秩合并操作会超时,因为枚举颜色最外层要一层,枚举外层每个点的颜色要一层,然后要在将那个颜色的最外层的点加入队列一层,共3层,在特例下会很慢(类似菊花连菊花,一个外层点很多的颜色,一下全部移到左边,一下全移到右边),用链表的话可以将第3层的时间变成O(1),优化很多时间。

代码部分:

#include<iostream>
#include<vector>
#include<list>
using namespace std;
int t,n,m,q,u,v,op,now,to;
vector<int>ho[800007];
list<int>lk[800007];
int fa[800007];
void init(){
	for(int i=0;i<n;i++){
		fa[i]=i;
		ho[i].clear();
		lk[i].clear();
		lk[i].push_back(i);
	}
}
int fin(int p){
	if(p==fa[p])return p;
	else{
		return fa[p]=fin(fa[p]);
	}
}
void solve(){
	if(op!=fa[op]){
		return;
	}
	int cnt=lk[op].size();
	while(cnt--){
		now=lk[op].front();
		lk[op].pop_front();
		for(int i=0;i<ho[now].size();i++){
			to=fin(ho[now][i]);
			if(to!=op){
				fa[to]=op;
				lk[op].splice(lk[op].end(),lk[to]);
			}
		}
	}
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		init();
		for(int i=1;i<=m;i++){
			scanf("%d%d",&u,&v);
			ho[u].push_back(v);
			ho[v].push_back(u);
		}
		scanf("%d",&q);
		while(q--){
			scanf("%d",&op);
			solve();
		}
		for(int i=0;i<n;i++){
			printf("%d ",fin(i));
		}
		puts("");
	}
}

posted @ 2020-07-22 14:02  ccsu_madoka  阅读(168)  评论(0编辑  收藏  举报