数据结构[并查集](2024/2/1)

并查集  

数据结构[并查集](2024/2/1)_第1张图片

1、定义及作用:是一种非常精巧而实用的树型数据结构,主要用于处理一些不相交集合的合并问题。

2、用途:求连通子图、求最小生成树的Kruskal算法和求最近公共祖先(LCA)等。

3、并查集的基本操作:

(1)初始化init。

(2)查询find。

(3)合并unionn。

4、主要构成:

整形数组pre[ ]  :记录每个点的前驱节点是谁。

函数find(x):查找指定节点x属于哪个集合。

函数join(x,y) :合并两个节点x和y。

初始化  

数据结构[并查集](2024/2/1)_第2张图片

int fa[MAXN];
void init(int n)
{
  for(int i=1;i<=n;i++)
     fa[i]=i;
}

假如有编号为1, 2, 3, ..., n的n个元素,我们用一个数组fa[]来存储每个元素的父节点(因为每个元素有且只有一个父节点,所以这是可行的)。一开始,我们先将它们的父节点设为自己。

查询 

int find(int i)
{
    if(fa[i] == i)     //递归出口
        return i;
    else
        return find(fa[i]);    //不断往上查找
}
//未进行路径压缩,效率较低

查询:一层一层访问父节点,直至根节点(根节点的标志就是父节点是本身)。要判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。

合并  

void unionn(int i,int j)
{
   int i_fa=find(i);   //找到i的代表元素
   int j_fa=find(j);   //找到j的代表元素
   fa[i_fa]=j_fa;   //i的代表元素指向j的代表元素
}

合并操作也是很简单的,先找到两个集合的代表元素,然后将前者的父节点设为后者即可。当然也可以将后者的父节点设为前者,这里暂时不重要。本文末尾会给出一个更合理的比较方法。

路径压缩  

数据结构[并查集](2024/2/1)_第3张图片

只要我们在查询的过程中,把沿途的每个节点的父节点都设为根节点即可。

路径压缩 

 查找时优化
int find(int x)
{
    if(x == fa[x])
        return x;
    else{
        fa[x] = find(fa[x]);  //父节点设为根节点
        return fa[x];         //返回父节点
    }
}

或(简化版)

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

在每次查找时,使查找路径上的每个节点都指向根节点。

合并时优化 

权值:此节点的高度。

如果i作为父节点更好,就让i作为父亲(代表元素),否则,j作为父亲。

【让权值更大的当父亲。】

e.g.

合并i和j

若R[i]>R[j],则fa[j]=i; 
若R[i] 若R[i]==R[j],则都可以。
当合并1和5时,由于R[1]>R[5],则uset[5]=1,让5的父节点为1。否则,就会让树的高度增加,查询效率就降低了。

今日刷题 

轴对称 
「GMOI R2-T1」轴对称

题目描述

你有一个 n 行 m 列的图片(矩阵),该图片的像素为 n*m。

初始时,所有像素块均为黑色,RGB 是 (0,0,0)。每一次操作可以将一个像素块的 RGB 中的一个数字改变。

在每次操作过后,请你输出图片是否左右对称?

左右对称:即对于任何的 i,j,总满足第 i 行第 j 列的像素与第 i行第 m-j+1 列的像素的 RGB 值相等。

输入格式

第一行三个整数 n,m,q, q代表操作次数。

接下来 q 行,每行输入四个整数 i,j,t,c,表示将第 i 行第 j列的格子的 RGB 值的第 t 个数增加 c,任何一个 RGB 值的任何一个数如果超出 $255$ 则自动对 $256$ 取模。

输出格式

每次操作过后,如果图片左右对称,输出 `Yes`,否则输出 `No`。每组询问的输出之间用换行隔开。

样例

样例输入

6 6 9
1 2 3 4
5 6 3 4
1 5 3 4
5 1 3 4
1 3 2 260
1 4 2 4
2 2 3 5
2 5 3 7
2 2 3 258

样例输出 

No
No
No
Yes
No
Yes
No
No
Yes

AC代码如下:

#include     //万能头文件
using namespace std;
struct RGB
{
  long long R,G,B;
}a[105][105];
long long c;
int n,m,q,i,j,t,k;
bool judge()
{
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if((a[i][j].R!=a[i][m-j+1].R)&&(a[i][j].B!=a[i][m-j+1].B)&&(a[i][j].G!=a[i][m-j+1].G))
			{
				return 0;
			}
		}
   }
   return 1;
}
int main()
{
	cin>>n>>m>>q;
	int flag=1;
	for(k=1;k<=q;k++)
	{
		cin>>i>>j>>t>>c;
		if(t=1)
		{
			a[i][j].R+=c;
			a[i][j].R%=256;   //不要忘了对256取模
       //不能直接判断两个点是否相同,因为如果上次加完不对称,这次那个点可能依然不对称
		}
		if(t=2)
		{
			a[i][j].G+=c;
			a[i][j].G%=256;
		}
		if(t=3)
		{
			a[i][j].B+=c;
			a[i][j].B%=256;
		}
		if(judge())
		{
			cout<<"Yes"<

今日的学习终于结束了!!希望大家有一定的收获!

                                                             ⊙▽⊙

你可能感兴趣的:(数据结构,算法,学习)