LA3027之並查集

2021-06-13 04:43:19 字數 1347 閱讀 7900

在處理一些有n個元素的合併於查詢問題時,我們經常會使用到並查集(union-find set)這樣一種樹形資料結構來處理,一般來說這樣的問題都是看似很簡單,但是資料量很大,容易超時,但是採用並查集這種資料結構卻能很容易解決這些問題。

一般來說,並查集使用陣列來實現,它實現的功能也很簡單,主要涉及兩個基本操作:

1.合併(union)兩個不相交集合

2.判斷兩個元素是否屬於同一集合(find).

基本操作:

1.union(x, y)

首先,初始化乙個陣列p[ ],其中p[ i ] = i,即每個節點都初始化為自己的父節點,union主要就是分別找到x和y所屬集合的根節點root,將其中乙個root指向另乙個root,即p[root1] = p[root2].

2.find(x)

遞迴的方式找到x所在集合的根節點root 。

3.路徑壓縮

可以看出來,經過union實現的集合的結構可能會是乙個只有一條鏈的樹,那麼這樣的話每次find操作的複雜度都會達到o( n ),為了避免這種情況,便有了一種巧妙的方法,因為find操作時遞迴的實現,每次遞迴中找到root節點時就將所有子孫節點都指向該節點,這樣的話以後每次find操作都將達到o(1)的複雜度,這就是路徑壓縮。

4.按秩合併

在union時,每次都將節點數較少的集合指向節點數多的集合,這樣的話可以使得最終集合的高度降低,使查詢更快。

例程:

int father[max]; /*father[x]表示x的父節點*/

int rank[max]; /*rank[x]表示x的秩*/

void init(void)

else

}

並查集作為一種高效的資料結構有很多應用,例如:求無向圖的連通分量個數,lca問題,帶限制的作業排序,求最小生成樹等,下面這題la3027便是利用並查集求出無向圖的連通分量個數從而求解。

這個題目中,我們將每個元素看成乙個頂點,而每個簡單化合物就是一條邊,當有k個頂點並有k條邊時,說明這些邊構成了乙個環,即無向圖的連通分量,所以我們只需要求出有多少個連通分量即可,使用並查集實現,**如下:

#include #include using namespace std;

int p[100001];

int sum;

int find_root(int x)

void union_set(int x, int y){

x = find_root(x);

y = find_root(y);

if(x==y){

sum++;

//cout<<"#"<

並查集 並查集

本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...

LA 4730 Kingdom 線段樹 並查集

la 4730 題意 有n個帶座標的城市,和m個操作,每次操作 road a b,連線a,b城市成為乙個州 或者 line c,查詢y c的水平線和多少個州相交以及這些州一共包含多少個城市。思路 可以把每個城市的x座標忽略,把縱座標看做線段樹的區間,乙個點就相當於更新區間 y,y 一條線就相當於更新...

並查集 線段樹 LA 4730 Kingdom

題目傳送門 題意 訓練指南p248 分析 第乙個操作可以用並查集實現,儲存某集合的最小高度和最大高度以及城市個數。運用線段樹成端更新來統計乙個區間高度的個數,此時高度需要離散化。這題兩種資料結構一起使用,聯絡緊密。include using namespace std const int n 1e5...