1、定义及作用:是一种非常精巧而实用的树型数据结构,主要用于处理一些不相交集合的合并问题。
2、用途:求连通子图、求最小生成树的Kruskal算法和求最近公共祖先(LCA)等。
3、并查集的基本操作:
(1)初始化init。
(2)查询find。
(3)合并unionn。
4、主要构成:
整形数组pre[ ] :记录每个点的前驱节点是谁。
函数find(x):查找指定节点x属于哪个集合。
函数join(x,y) :合并两个节点x和y。
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的代表元素
}
合并操作也是很简单的,先找到两个集合的代表元素,然后将前者的父节点设为后者即可。当然也可以将后者的父节点设为前者,这里暂时不重要。本文末尾会给出一个更合理的比较方法。
只要我们在查询的过程中,把沿途的每个节点的父节点都设为根节点即可。
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]
当合并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"<
今日的学习终于结束了!!希望大家有一定的收获!
⊙▽⊙