1. 程式人生 > 實用技巧 >HUAWEI-NAT

HUAWEI-NAT

並查集

並查集是一種可以動態維護若干個不重疊的集合,並支援合併與查詢的資料結構,並查集包含如下兩個基本操作。
\(1\).get,查詢一個元素屬於哪一個集合。
\(2\).merge,把兩個集合合併成一個集合。
並查集的關鍵點是要定義一種合理有效的歸屬關係表示方法。採用一棵樹形結構儲存每個集合,樹上的每個節點都是一個元素,樹根是集合代表的元素。。整個的並查集實際上是一個森林(若干棵樹)。我們仍然可以維護一個數組\(fa\)來記錄這個森林,用\(fa[x]\)儲存x的父節點。特別的,令樹根的fa值等於它自己。故,在合併兩個集合時,只需連線兩個樹根(令其中一個樹根為另一個樹根的子節點,即\(fa[root1]\)

=\(root2\)

路徑壓縮

對於一棵樹,其中的每個節點都是屬於根節點為代表的集合下的,在我們對任意節點進行get操作時,我們可以把訪問過的每個節點都指向樹根,這種操作叫路徑壓縮,採用路徑壓縮的並查集的每次\(get\)操作的均攤複雜度為\(O(logn)\)

1.並查集的儲存與初始化

使用一個數組fa來儲存父節點(根的父節點為自己)

int fa[size];
for(int i=1;i<=n;i++) fa[i]=i;//設有n個元素,起初所有元素各自構成一個獨立的集合,即有n棵1個點的樹

2.並查集的\(get\)操作

//若x時樹根,則x就是集合代表,否則遞迴訪問fa[x]直至根節點。
int get(int x){
      if(x!=fa[x]) fa[x]=get(fa[x])
      return fa[x];
}

3.並查集的merge操作

合併元素x和元素y所在的集合,等價於讓x的樹跟作為y的樹根的子節點。、
 void merge(int x,int y){
  fa[get(x)]=get(y)