顧名思義,就是在維護集合關係的樹中新增邊權的並查集,這樣做可以維護更多的資訊。
引入題目:
比如這道題,如果使用普通的並查集則無法處理,因為普通的並查集只能夠刻畫兩個物品是否屬於同乙個集合。因此這時候就要使用能夠記錄更多資訊的帶權並查集。
在閱讀前,需要先掌握並查集的知識。結合題目講解:
對於乙個物種(一類動物),如果存在它吃另乙個物種的關係,則讓它的度數比另乙個物種多 \(1\) 。更嚴格地說,我們記該物種為a
(並非題意中的a
),另乙個物種是b
,它們對應的度數為d
,那麼有 \(d[a]=d[b]+1\) 。如圖:
那麼有了這樣的規定,便有如下性質:
從上面的性質可以看出,兩個物種的關係與它們的模數(這題是 \(mod3\) )餘多少關係密切相關,因此接下來我們也會著重考察兩個數之間的這種關係。利用度數以及並查集,即可將各種動物之間的關係刻畫清楚:
這裡依然對a
,b
進行討論,為了方便,我們記a
的祖宗(根節點)為pa
,b
的祖宗(根節點)為pb
。
綜上,我們的討論將所有情況覆蓋了。
路徑壓縮:
根據並查集的性質,如果不進行路徑壓縮,時間複雜度將會退化到 \(o(n)\) 。因此帶權並查集也要進行路徑壓縮,那麼主要問題就是解決如何維護d
(度數)的問題:
概括地說,就是在查詢到某個點的時候,在搜尋它的祖宗時遞迴地求出路上所有結點的度數,那麼它的度數就是d[x]+=d[f[x]]
。
如上圖,pa
在一次操作中併入了pb
。
而在另一次操作中,對a
的進行了查詢(求祖宗),便有如下路徑壓縮的並更新d
的過程:
遞迴地找出祖宗pb
。
pa
的祖宗就是pb
,度數在合併的時候已經求出來了,所以更新 \(0\)。
c
的父親節點是pa
,合併的時候並沒有更新(因此記錄的是距離pa
的度數),度數需要加上 \(d[pa]\),然後進行路徑壓縮。
a
的父親節點是c
,在上一步更新了,所以度數加上 \(d[c]\) 即可,類似的,進行路徑壓縮。
(這裡可能有點難理解,不過只要記住:所謂的d[x]
指的是節點x
相對於它父節點的度數即可)
不理解的地方可以結合**理解放上**:(很短的)
#includeusing namespace std;
const int n=5e4+5;
int f[n],d[n];
int find(int x)
return f[x];
}int main()
if(a==b && op==2)
int pa=find(a),pb=find(b);
int t= op==2;
if(pa==pb)else
}cout
分析:思路完全類似於食物鏈那題。
**#includeusing namespace std;
const int n=2e4+5;
unordered_maph;
int n,m;
int f[n];
int d[n];
int get(int x)
int find(int x)
return f[x];
}int main()
}else
}cout
資料結構 帶權 種類並查集
給出乙個區間的長度 n,及 m 個子區間和,形如 x y z,表示 子區間 x,y 的和為 z 如果乙個 子區間和 與前面的 子區間和 衝突,即為錯誤 而且這個 子區間和 將在接下來的判斷中被忽略 求總錯誤個數。帶權並查集 include include include using namespac...
樹形結構 並查集 帶權並查集
定義 帶權並查集即是結點存有權值資訊的並查集。適用 當兩個元素之間的關係可以量化,並且關係可以合併時,可以使用帶權並查集來維護元素之間的關係。權值 帶權並查集每個元素的權通常描述其與並查集中祖先的關係,這種關係如何合併,路徑壓縮時就如何壓縮。與並查集的區別 帶權並查集可以推算集合內點的關係,而一般並...
並查集,帶權並查集
題意 ignatius過生日,客人來到,他想知道他需要準備多少張桌子。然而一張桌子上面只能坐上相互熟悉的人,其中熟悉可定義成為a與b認識,b與c認識,我們就說a,b,c相互熟悉 例如a與b熟悉and b與c熟悉,d與e熟悉,此時至少需要兩張桌子。輸入 t表示樣例個數,n表示朋友個數,朋友從1到n編號...