這橙題無非只是模板題,套並查集模板ac!並查集的演算法思想十分值得大家學習!
老規矩,先看題目。
題目告訴我們要對n個元素進行m次操作,對其中的一些進行合併操作,並輸出兩個集合的合併情況。這裡我們首先會想到用並查集!沒錯,但萌新們不用怕,我接下來講解一下並查集的思路,你們就明白了!
並查集:樹形資料結構
聽起來比較簡單,實現起來也很簡單。我們分3步學會模板!
首先我們先要學會構建find函式(查詢乙個結點的根結點)
拿這題舉例,我們通過乙個陣列f[10010] (開小容易re或tle)。如果其祖先等於自己,直接return回去。否則通過遞迴不斷迴圈,最後找出結點的根結點。
ok~那我們接下來就看看find函式的定義吧!
1關於find函式還有個路徑壓縮的知識點:int find(int
x)
1else
return find(f[x]);//
遞迴返回,乙個個找它的父結點,最終找到根節點 1
else
return f[x]=find(f[x]);//
直接將結點連到其根節點上。find定義**最後一句就是它
第二個**優化時間的方法就叫路徑壓縮。
我們看兩張圖就理解了!
如圖,求這棵樹所有結點的祖先,時間複雜度取決於這棵樹的深度,是o(n²)。
如圖,求這棵樹所有結點的祖先,時間複雜度取決於結點的個數,是o(n)。
∴路徑壓縮能優化時間複雜度。
接下來來是並,我們合併兩個結點的根結點時需要用到查(find函式)!
那我們就看看join函式的定義吧!
1最後一步直接判斷兩個結點所在集合是否有共同根結點。用find函式就可以了!void join(int x,int
y)
那我們再看看判斷**吧!
1好了,我們的思路就講到這裡,下面是ac**!if(find(a)==find(b))
2 cout<
/如果結點a和b有相同的根結點,則輸出「y」
3else
4 cout<
/否則輸出「n」
(注釋版)
1 #include2(無注釋版)using
namespace
std;
3int n,m,f[10010],a,b,c;//
陣列f[i]記錄i的根結點
4int find(intx)8
void join(int x,int
y)12
int main()
26return0;
27 }
1 #include2並查集分3步:using
namespace
std;
3int n,m,f[10010
],a,b,c;
4int find(intx)8
void join(int x,int
y)12
intmain()
26return0;
27 }
1. 把每個結點所在的集合初始化為它自己
2. 將兩個不同集合的結點合併(join函式)
3. 查詢結點所在集合的根結點(find函式)
P3367 模板 並查集
題目描述 如題,現在有乙個並查集,你需要完成合併和查詢操作。輸入格式 第一行包含兩個整數 n,m 表示共有 n 個元素和 m 個操作。接下來 m 行,每行包含三個整數 zi,xi,yi。當 zi 1 時,將 xi與 yi所在的集合合併。當 zi 2 時,輸出 xi與 yi是否在同一集合內,是的輸出 ...
P3367 模板 並查集
如題,現在有乙個並查集,你需要完成合併和查詢操作。輸入格式 第一行包含兩個整數n m,表示共有n個元素和m個操作。接下來m行,每行包含三個整數zi xi yi 當zi 1時,將xi與yi所在的集合合併 當zi 2時,輸出xi與yi是否在同一集合內,是的話輸出y 否則話輸出n 輸出格式 如上,對於每乙...
P3367 模板 並查集
如題,現在有乙個並查集,你需要完成合併和查詢操作。輸入格式 第一行包含兩個整數n m,表示共有n個元素和m個操作。接下來m行,每行包含三個整數zi xi yi 當zi 1時,將xi與yi所在的集合合併 當zi 2時,輸出xi與yi是否在同一集合內,是的話輸出y 否則話輸出n 輸出格式 如上,對於每乙...