2020牛客暑期多校训练营Operating on a Graph(并查集,启发式合并/链表)

Operating on a Graph

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例1

输入

5
4 3
0 1
1 2
2 3
4
0 1 3 0
4 3
0 1
1 2
2 3
2
0 2
4 3
0 1
1 2
2 3
2
0 3
4 1
1 3
1
2
5 5
0 1
0 2
1 2
1 3
3 4
3
4 4 0

输出

0 0 0 0
2 2 2 2
0 0 3 3
0 1 2 3
0 0 0 0 0

说明

在这里插入图片描述

题目大意

给定一张n个点,m条边的图。每个点都有各自的颜色1,2,3……n。接下来进行q次染色操作。每次操作给定一个qi,要求把所有的颜色为qi的点的相邻的所有颜色不为qi的点,染色为qi

分析

题意有点绕,接下来深解一下题意。其实就是对于每个颜色进行一次BFS式的扩展,如图。
在这里插入图片描述
在这里插入图片描述
首先分析染色的过程,每个点的周边部分被染色的过程就像并查集的过程,把周围的颜色变成这个点的颜色。
所以我们可以定义一个col[],表示每个点的颜色,如果被染色,那就用并查集查找一下它的颜色,然后更改。

但是这样有点问题。就是上图中的第二个图。所有被染色的点都要作为源点进行染色。(样例里面能调出来,太良心了)因此需要一个vector的合并,在染色的同时,把连边的信息也要同时转移过去。

于是这里就要用到一个启发式合并,把小的集合复制到大的集合里去,也叫拍脑瓜合并。

WAWAWA

拒绝骚操作,从我做起。 之前翻大佬代码的时候看到如此操作

for(scanf("%d",&t);t--;)

结果……被xinjun笑了一顿……
还有,并查集时千万记得路径压缩,否则T上天。(大概是好久不打并查集的锅……

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=8e5+10;
int col[MAXN];
int gcl(int x){return col[x]==x?x:col[x]=gcl(col[x]);}//并查集,路径压缩!!
vector<int> vec[MAXN];
int main()
{
	int t,n,m,q,qq,x,y;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n;i++) vec[i].clear(),col[i]=i;//初始化
		for(int i=1;i<=m;i++){
			scanf("%d%d",&x,&y);
			vec[x].push_back(y);
			vec[y].push_back(x);
		}//存边
		scanf("%d",&q);
		for(int i=1;i<=q;i++){
			scanf("%d",&qq);
			if(gcl(qq)==qq){//如果qq这种颜色还有,则可以染色
				vector<int> now=vec[qq];//把vec[qq]取出来,防止循环出错
				vec[qq].clear();
				for(int j=0;j<now.size();j++){
					int nxt=gcl(now[j]);
					if(nxt!=qq){
						col[nxt]=qq;//染色
						if(vec[nxt].size()>vec[qq].size()) swap(vec[nxt],vec[qq]);
						for(int k=0;k<vec[nxt].size();k++) vec[qq].push_back(vec[nxt][k]);
						//启发式合并,复制小的
					}
				}
			}
		}
		for(int i=0;i<n;i++) printf("%d ",gcl(i));printf("\n");
	}
}

END

WA的概率与骚操作的多少成正比。

猜你喜欢

转载自blog.csdn.net/zhangchizc/article/details/107486988