1. 红黑树
1.1 定义
(1) 结点是红色或黑色。
(2) 根结点是黑色。
(3) 所有叶子都是黑色。(叶子是NIL结点)
(4) 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
(5) 从任一节结点其每个叶子的所有路径都包含相同数目的黑色结点。
1.2 性质
从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。
1.3 平衡操作
1.3.1 插入
1.3.1.1 被插入的节点是根节点。
直接把此节点涂为黑色。
1.3.1.2 被插入的节点的父节点是黑色。
什么也不需要做。
1.3.1.3 被插入的节点的父节点是红色。
[1] 当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。
(1) 将“父节点”设为黑色。
(2) 将“叔叔节点”设为黑色。
(3) 将“祖父节点”设为“红色”。
(4) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。
[2] 叔叔节点是黑色,且当前节点是其父节点的右孩子
(1) 将“父节点”作为“新的当前节点”。
(2) 以“新的当前节点”为支点进行左旋。
[3] 叔叔节点是黑色,且当前节点是其父节点的左孩子
(1) 将“父节点”设为“黑色”。
(2) 将“祖父节点”设为“红色”。
(3) 以“祖父节点”为支点进行右旋。
1.3.2 删除
1.3.2.1 x指向一个"红+黑"节点。
将x设为一个"黑"节点即可。
1.3.2.2 x指向根。
将x设为一个"黑"节点即可。
1.3.2.3
[1] x的兄弟节点是红色。
(1) 将x的兄弟节点设为“黑色”。
(2) 将x的父节点设为“红色”。
(3) 对x的父节点进行左旋。
(4) 左旋后,重新设置x的兄弟节点。
[2] x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色。
(1) 将x的兄弟节点设为“红色”。
(2) 设置“x的父节点”为“新的x节点”。
[3] x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的。
(1) 将x兄弟节点的左孩子设为“黑色”。
(2) 将x兄弟节点设为“红色”。
(3) 对x的兄弟节点进行右旋。
(4) 右旋后,重新设置x的兄弟节点。
[4] x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色。
(1) 将x父节点颜色 赋值给 x的兄弟节点。
(2) 将x父节点设为“黑色”。
(3) 将x兄弟节点的右子节设为“黑色”。
(4) 对x的父节点进行左旋。
2. 并查集
2.1 定义
用森林维护集合关系,支持合并、查询等操作。
2.2 优化
(1) 路径压缩
(2) 按秩合并
题目描述
一共有 n n n 个数,编号是 1 到 n 1 到n 1到n,最开始每个数各自在一个集合中。
现在要进行 m m m 个操作,操作共有两种:
M a b
,将编号为 a a a 和 b b b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Q a b
,询问编号为 a a a 和 b b b 的两个数是否在同一个集合中;
输入格式
第一行输入整数 n n n 和 m m m。
接下来
m
m
m 行,每行包含一个操作指令,指令为 M a b
或 Q a b
中的一种。
输出格式
对于每个询问指令 Q a b
,都要输出一个结果,如果
a
a
a 和
b
b
b 在同一集合内,则输出 Yes
,否则输出 No
。
每个结果占一行。
数据范围
1 < = n , m < = 1 0 5 1<= n,m <= 10^5 1<=n,m<=105
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
算法
C++ 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, m;
int p[N], r[N];
int find(int x){
//路径压缩
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int a, int b){
a = find(a), b = find(b);
//按秩合并
if(a == b) return;
if(r[a] > r[b]) p[b] = a;
else{
p[a] = b;
if(r[a] == r[b]) r[b] ++;
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
p[i] = i;
r[i] = i;
}
while(m --){
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if(*op == 'Q'){
if(find(a) == find(b)) puts("Yes");
else puts("No");
}
else merge(a, b);
}
return 0;
}