並查集的總結(數量 加權 擴充套件域 例題 萌新求贊)

2021-10-16 17:11:35 字數 4291 閱讀 8326

南昌理工acm
並查集屬於半模板資料結構

可以有很多種維護方式(後面我會舉幾個,我剛學一些,也不是很懂,萌新磕頭)

先說並查集怎麼用

for

(int i=

1;i<=n;i++

) p[i]

=i;///初始化,就是這麼簡單

再講合併之前我們要講一下路徑壓縮

如圖,就是將所以的點全部連到了他的最上面的節點,主要是為了減少查詢時間(高效)

**如下

int

find

(int x)

這就是俗稱找爸爸函式(字面意思)

合併兩個集合,很容易,只要把他的祖宗節點並到另乙個集合就行

查詢兩個集合,就是看看他們有沒有在乙個集合裡,就行。

int

find

(int x)

p[find

(a)]

=find

(b);

//合併集合if(

find

(a)==

find

(b))

puts

("yes");

//查詢集合

else

puts

("no"

);

這些就是整個並查集的核心(但這不是全部,這是半模板的資料結構)

剩下的主要靠你自己維護(下面介紹幾個比較好的並查集型別)

這裡先練一道模板題

**如下

#include

#include

using namespace std;

const

int n=

2e5+10;

int p[n]

;int n,m;

intfind

(int x)

intmain()

}return0;

}

- 並查集主要維護 有三

1 數量

2 種類

3 權重

在學習這三種之前我們看一道(關於反集思想的並查集,來感受一下並查集的魅力)

反集主要應用 就一句話

敵人的敵人就是朋友(夥伴們來題)

超經典 點開看看吧

**如下

大家在紙上畫一下就明白了

通過交替的反集思想來解決問題

是不是感覺到並查集 的強大

反正我是對這個東西,佩服的五體投地,**的太慘 /(ㄒoㄒ)/~~

這裡我推薦acwing這道新手題

**如下

#include

using namespace std;

const

int n=

1e5+10;

int p[n]

,sz[n]

;int n,m,a,b;

string str;

void

init()

}int

find

(int x)

void

merge

(int a,

int b)

intmain()

else

if(str==

"q1"

)else

}return0;

}

這裡主要是維護根節點的大小,不進行子節點不需要維護

所以只需要更新根節點的sz陣列就行了(size打不出來,就用sz了)

這種題型也比較常見,無非是換了一種寫法,相信大家可以認真對待

難搞的並查集來了

這裡我們一起講

用最經典的食物鏈吧,方便理解

食物鏈題目

這裡先上**

#include

using namespace std;

const

int n=

5e4+10;

int p[n*3]

;int n,m,ans;

intfind

(int x)

intmain()

}else}}

cout<

return0;

}

#include

#include

using namespace std;

const

int n=

5e4+10;

int p[n]

,r[n]

;int n,m,ans;

intfind

(int x)

return p[x];}

intmain()

else}}

cout<

return0;

}

這裡我給出兩種方法的詳解

這裡,詳細的講解了加權並查集

秦大佬 的講解 我覺得最好 關於擴充套件域並查集

再補充一道題,也很經典(加權並查集)

[noi2002]銀河英雄傳說 加權並查集

#include

#include

#include

#include

using namespace std;

const

int n=

1e6+10;

int p[n]

,sz[n]

,d[n]

;int n;

void

init()

intfind

(int x)

return p[x];}

intmain()

}else

}return0;

}

簡單題 這裡我用的是trie樹+並查集

#include

#include

using namespace std;

const

int n=

2e5+10;

int p[n]

;int son[n][58

],cut[n]

,idx;

int n,m;

intfind

(int x)

void

insert

(string a,

int k)

cut[p]

=k;}

intquery

(string a)

return cut[p];}

intmain()

for(

;m;m--

) cin>>n;

for(

;n;n--

)return0;

}

這是我的小小總結,希望大家能多多加油

萌新的我,才剛剛接觸**不久,路是那麼那麼遠

想想就傷心 ,演算法沒有盡頭啊

哭泣/(ㄒoㄒ)/~~

支援我一下下吧,希望得到大家的點讚

製作不易,謝謝大家

詳解 並查集高階技巧 加權並查集 擴充套件域並查集

可以理解為使用陣列實現的樹形結構,只儲存了每個節點的父節點 前驅 功能為 合併兩個節點 及其所在集合 查詢節點所屬集合的代表節點 可以理解為根節點 以6個元素為例 編號0到5 把0單獨劃分為乙個集合 把1,2,3,4劃分為乙個集合 把5單獨劃分為乙個集合。n個元素的並查集,只需要乙個容量為n的陣列f...

並查集的擴充套件域

核心思想 fa a 儲存與a同類的 fa a 1 n 儲存與a發生第一類關係的 fa a 2 n 儲存與a發生第二類關係的 fa a 3 n 儲存與a發生第三類關係的 分析將並查集中儲存節點關係的f陣列擴大2倍,1 n表示朋友,n 1 2 n表示敵人。那麼對於x,y,如果x和y是朋友,直接合併,如果...

True Liars 擴充套件域並查集

傳送門 每個點拆成兩個,表示好人或壞人 我們合併集合後,發現存在幾組對立的集合 也就是說這個集合和與它對立的集合只能選乙個 我們用rt1 i rt2 i 表示第i個集合 和 與第i個集合對立的集合 cnt1,cnt2表示該集合好人的個數 用f i j 表示到第i個集合,好人為j的方案數 同時記錄fr...