51集训-day3-G

原题链接:G-Operating on a Graph_2023牛客五一集训派对day3 (nowcoder.com)

题目理解:给你n个点,序号是0~n-1。然后给m个边,对应是两个点相互连接。最后给出q个点,如果该点没有变成“其他点的附属”,就将该点所有相邻的点都变成该点的“附属”。如果该点变成的“其他点的附属”,那就忽略这次操作。

整体思路:设置一个vector数组。其下角标就是对应某个序号的点。每个点对应的vector都存储各自相邻的边。然后题目给出q个点的时候,每次给出就将其看作该点所属的“阵营”——即该点及其附属,向该“阵营”的所有相邻点的一次“侵略”,然后将该所有相邻点设为给出的点的“附属”。

需要掌握的知识点1-并查集(用于我们维护哪个点是哪个点的“附属”),代码如下

int p[800000+5];  //对应各个点的序号
//并查集 
int find(int x)
{
	if(x!=p[x])p[x]=find(p[x]);  //这样大家都同时指向根部,在找的过程中就能修正,避免运行超时! 
	return p[x];
}

首先我们输入要操作的点,如果被侵略了就不做操作

cin>>x;  //第几个点 
if(x!=p[x])continue;  //已经被侵略就不做操作
	

如果没有被侵略就先使用vector数组b将当前该点x的所有相邻点提取出来,并将vector a[x]的内容清空以防止后期的元素重复。

b=a[x];a[x].clear();  //将被侵略点相邻的边都取出来,然后把当前相邻的点清空

然后接下来就是找x的所有相邻点,在并查集中设置对应的“附庸关系”,并在a[x]数组中添加上其所有的相邻点。

for(i=0;i<b.size();i++)
{
	y=find(b[i]); //相邻点所属于的颜色 
	if(x!=y)  //找到要侵略的点 
	{
		p[y]=x;  //将要侵略的点侵略
		//找要被侵略的点包含的所有相邻点
		if(a[x].size()<a[y].size())swap(a[x],a[y]);
		for(j=0;j<a[y].size();j++)
		{
			a[x].push_back(a[y][j]);
		}
	 } 
}  

最终就是按照格式输出答案

最终的AC代码:

#include <iostream>
#include <vector>
#include<string>
#include<sstream>
#include<math.h>
#include<map>
#include<set> 
#include<cstring>
#include<algorithm>
using namespace std;
vector<int>a[800000+5],b;//存储 “被侵略的点链接的边” 
int p[800000+5];
//并查集 
int find(int x)
{
	if(x!=p[x])p[x]=find(p[x]);  //这样大家都同时指向根部,在找的过程中就能修正远点 
	return p[x];
}
void solveg()
{
	
	int t;
	cin>>t;
	while(t--)
	{
		int n,m,i,j,x,y,q;
		cin>>n>>m;
		for(i=0;i<=n;i++) //初始化 
		{
			p[i]=i;
			a[i].clear(); 
		}
		for(i=1;i<=m;i++)
		{
			cin>>x>>y;
			//两者互相是对方的邻接点 
			a[x].push_back(y);
			a[y].push_back(x);
		}
		cin>>q;
		while(q--)
		{
			cin>>x;  //第几个点 
			if(x!=p[x])continue;  //已经被侵略就不做操作
			//b存储当前x的所有相邻点,然后把x当前存储的相邻点清空 
			// 接下来到了被侵略的点的处理
			b=a[x];a[x].clear();  //将被侵略点相邻的边都取出来,然后把当前相邻的点清空
			//遍历当前相邻的点
			for(i=0;i<b.size();i++)
			{
				y=find(b[i]); //相邻点所属于的颜色 
				if(x!=y)  //找到要侵略的点 
				{
					p[y]=x;  //将要侵略的点侵略
					//找要被侵略的点包含的所有相邻点
					if(a[x].size()<a[y].size())swap(a[x],a[y]);
					for(j=0;j<a[y].size();j++)
					{
						a[x].push_back(a[y][j]);
					}
				 } 
			}  
		}
		for(i=0;i<n;i++)
		{
			cout<<find(i)<<" ";
		} 
		cout<<endl;
	}
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solveg();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值