并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗 并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗 并查集简单来说就是维护并判断多个族谱中的两人是否有相同的祖宗
用 f 来维护每个人的父亲, f [ i ] 表示 i 的父亲 \small{用}\mathbf{f}来维护每个人的父亲,\mathbf{f[i]} 表示\mathbf{i}的父亲 用f来维护每个人的父亲,f[i]表示i的父亲
初始化将每个人的父亲置为自己 \small{初始化将每个人的父亲置为自己} 初始化将每个人的父亲置为自己
for(int i = 1; i <= n; i ++)
f[i] = i;
写一个函数来查找某个人的祖宗 \small{写一个函数来查找某个人的祖宗} 写一个函数来查找某个人的祖宗
int getfather(int k){
if(f[k] == k) return k;
else return getfather(f[k]);
会得到这样一个关系 \small{会得到这样一个关系} 会得到这样一个关系
下面是路径压缩 \small{下面是路径压缩} 下面是路径压缩
int getfather(int k){
if(f[k] == k) return k;
return f[k] = getfather(f[k]);
}
压缩后则会是这样的关系 \small{压缩后则会是这样的关系} 压缩后则会是这样的关系
显然,这样在查询上会明显加快,时间复杂度为 O ( n log n ) \small{显然,这样在查询上会明显加快,时间复杂度为}O(n\log n) 显然,这样在查询上会明显加快,时间复杂度为O(nlogn)
再看下面这种情况 \small{再看下面这种情况} 再看下面这种情况
如果将
4
合并到
1
上面,树的深度变为
4
,但是将
1
合并到
4
上面,树的深度依然是
3
,
\small{如果将4合并到1上面,树的深度变为4,但是将1合并到4上面,树的深度依然是3,}
如果将4合并到1上面,树的深度变为4,但是将1合并到4上面,树的深度依然是3,
显然,将
1
合并在
4
上可以降低搜索层数,即按秩合并
\small{显然,将1合并在4上可以降低搜索层数,即按秩合并}
显然,将1合并在4上可以降低搜索层数,即按秩合并
按秩合并的总复杂度为 O ( n log n ) ,均摊为 O ( log n ) \small{按秩合并的总复杂度为\mathbf{O(n\log n)},均摊为\mathbf{O(\log n)}} 按秩合并的总复杂度为O(nlogn),均摊为O(logn)
解析
因为每次合并,所有数据结构大小为
n
,要合并的两个数据结构的大小分别
\small\mathbf{解析}\small\quad因为每次合并,所有数据结构大小为n,要合并的两个数据结构的大小分别
解析因为每次合并,所有数据结构大小为n,要合并的两个数据结构的大小分别
为
x
,
y
(
n
≥
x
≥
y
)
则时间复杂度为
O
(
y
)
,数据结构大小变为
x
+
y
,最坏的情况下也
\small{为x,y(n \ge x\ge y)则时间复杂度为\mathbf{O(y)},数据结构大小变为x+y,最坏的情况下也}
为x,y(n≥x≥y)则时间复杂度为O(y),数据结构大小变为x+y,最坏的情况下也
只能是
O
(
n
)
,又因为最多只能合并
log
n
次,所以总时间复杂度为
O
(
n
log
n
)
)
\small{只能是\mathbf{O(n)},又因为最多只能合并\mathbf{\log n}次,所以总时间复杂度为\mathbf{O(n\log n))}}
只能是O(n),又因为最多只能合并logn次,所以总时间复杂度为O(nlogn))
按秩合并 \small{按秩合并} 按秩合并
void Union(int a,int b){
int x = getfather(a);
int y = getfather(b);
if(x == y) return;
if(deep[x] > deep[y]) f[y] = x;
else {
if(deep[x] == deep[y]) deep[y] ++;
f[x] = y;
}
}
完整代码 \small{完整代码} 完整代码
struct dsu{
int f[100005];
int deep[100005];
int getfather(int k){
if(f[k] == k) return k;
return f[k] = getfather(f[k]);
}
void Union(int a,int b){
int x = getfather(a);
int y = getfather(b);
if(x == y) return;
if(deep[x] > deep[y]) f[y] = x;
else {
if(deep[x] == deep[y]) deep[y] ++;
f[x] = y;
}
}
void mem(int n){
for(int i = 1; i <= n; i ++){
f[i] = i;
deep[i] = 1;
}
}
};