牛客多校3 - Operating on a Graph(并查集+链表合并)

题目链接:点击查看

题目大意:给出一个由 n 个点和 m 条边组成的无向图,每个点初始时都有颜色 i ,i ∈ [ 0 , n - 1 ] ,接下来有 q 次操作,每次操作会给出一种颜色 x ,分两种情况讨论:

  1. 如果颜色为 x 的点不存在,则跳过此次操作
  2. 如果颜色为 x 的点存在,则将颜色为 x 的点的相邻的所有颜色块,都染成 x 的颜色

问最后每个点的颜色是什么

题目分析:合并问题不难想到并查集,对于每个点的颜色可以用并查集来维护,不过如果暴力更新的话肯定会 T ,有一个比较显然且比较重要的结论就是,每个点至多被遍历一次,因为如果当某个点被遍历过一次后,那么其相邻的所有点肯定和当前的点都变为同一个颜色了,接下来无论如何操作,再遍历这个点肯定是没有任何进展的了,所以基于这个性质,我们可以用链表配合并查集实现模拟

首先并查集的 f 数组配合 find 函数用来维护每个点被染成的颜色,初始化为每个点本身,其次每个颜色都建立一个链表,用来储存当前颜色下有多少个点被染成了相同的颜色

对于每一个询问的颜色 x ,如果不存在的话,直接跳过即可,如果存在的话,可以遍历一遍相应的链表进行扩展,根据上面的性质可知,遍历过的元素直接删除掉即可,对于新加入的元素,可以利用链表的 splice 方法,这个方法可以 O( 1 ) 合并两个链表,如此一来,整体的时间复杂度也只是 O( n * a + m ),a 是并查集的时间开销

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<list>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;
 
const int N=8e5+100;

list<int>li[N];

vector<int>node[N];

int f[N];

void init(int n)
{
	for(int i=0;i<n;i++)
	{
		f[i]=i;
		li[i].clear();
		li[i].push_back(i);
		node[i].clear();
	}
}

int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}

void merge(int x,int y)//xx合并到yy 
{
	int xx=find(x);
	int yy=find(y);
	if(xx!=yy)
	{
		f[xx]=yy;
		li[yy].splice(li[yy].end(),li[xx]);
	}
}

void update(int x)
{
	if(x!=find(x))
		return;
	int sz=li[x].size();
	while(sz--)
	{
		int u=li[x].front();
		li[x].pop_front();
		for(auto v:node[u])
			merge(v,u);
	}
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		init(n);
		while(m--)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			node[u].push_back(v);
			node[v].push_back(u);
		}
		int q;
		scanf("%d",&q);
		while(q--)
		{
			int x;
			scanf("%d",&x);
			update(x);
		}
		for(int i=0;i<n;i++)
			printf("%d ",find(i));
		puts("");
	}













    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/107448782
今日推荐