並查集可用來解決一些元素分組的問題,管理一系列不相交的集合
原理 起初有1~n
個元素,它們分別指向自己,父節點即為自己
當兩個元素要合併時,用其中乙個元素指向另外乙個fa[i] = j
,
代表 i 的父元素是 j 。
// 查詢根節點
int find(int x)
void merge(int i,int j)
// 一句話
int find(int x)
// 拆分
int find(int x)
}
一共有 n個數,編號是 1∼n,最開始每個數各自在乙個集合中。
現在要進行 m個操作,操作共有兩種:
m a b
,將編號為 a和 b 的兩個數所在的集合合併,如果兩個數已經在同乙個集合中,則忽略這個操作;
q a b
,詢問編號為 a和 b 的兩個數是否在同乙個集合中;
模板
#include using namespace std;
const int n = 100010;
int p[n];
int find(int x)
int main()
}return 0;
}
自己寫的
#includeusing namespace std;
const int n = 100010, m = 100010;
int fa[n];
// 查詢父節點,順便將路徑上的點都指向集合中的根節點
int find(int x)
// 合併
void merge(int i, int j)
// 查詢是否在同一集合
bool query(int i, int j)
int main() else if(op == 'q')
}return 0;
}
給定乙個包含 n個點(編號為1∼n)的無向圖,初始時圖中沒有邊。
現在要進行 m個操作,操作共有三種:
c a b
,在點 a 和點 b 之間連一條邊,a 和 b 可能相等;
q1 a b
,詢問點 a 和點 b 是否在同乙個連通塊中,a 和 b 可能相等;
q2 a
,詢問點 aa 所在連通塊中點的數量;
本題主要是要記錄連通塊中點的數量,初始化乙個size
陣列,當合併的時候更新根節點的size
陣列就可以了。
自己寫的
#include #include using namespace std;
const int n = 100010;
int p[n], size[n];
int find(int x)
// 合併時同乙個集合不一定所有節點指向根節點,但查詢時,find函式路徑壓縮會讓乙個集合中元素都指向根節點。
void merge(int i, int j)
int main()
while (m -- )
}else if(op == "q1") else
}return 0;
}
模板
#include using namespace std;
const int n = 100010;
int n, m;
int p[n], cnt[n];
int find(int x)
int main()
while (m -- )
}else if (op == "q1")
else
}return 0;
}
普通的並查集僅僅記錄的是集合的關係,這個關係只是同乙個集合或不在同一集合。而帶權並查集,不僅記錄集合的關係,還記錄著集合內元素的關係(或者說元素連線線的權值)。
解決這類問題主要是要明確距離在題目中指的是什麼,
並查集小結
並查集一類的題目最近也做了許多,相對來說,還是比較容易理解和實現的。最早開始接觸並查集是在學習用kruskal求最小生成樹的時候,後來接觸的題目多了,發現並查集還有好多用途,比如典型的判環,區間問題等等。學習並查集的過程中我發現,並查集的路徑壓縮十分重要,有時候對於題目限定的條件,在路徑壓縮的過程中...
並查集小結
小做了一下並查集相關的題目。就從最基礎的開始吧。首先是並查集的介紹,非常好的一篇博文 其次就是一些習題了。首先是這道題目 poj1308 is it a tree?整道題就是需要你判斷給出乙個有向圖是不是一棵樹。這裡會使用到並查集來判環,算是並查集的基礎應用 也就是判斷元素是不是屬於乙個集合 然後是...
並查集小結
並查集一類的題目最近也做了許多,相對來說,還是比較容易理解和實現的。最早開始接觸並查集是在學習用kruskal求最小生成樹的時候,後來接觸的題目多了,發現並查集還有好多用途,比如典型的判環,區間問題等等。學習並查集的過程中我發現,並查集的路徑壓縮十分重要,有時候對於題目限定的條件,在路徑壓縮的過程中...