帶權並查集 POJ1988

2021-07-14 20:17:39 字數 1418 閱讀 4654

題目鏈結在這裡

題目大概的意思就是兩種操作,一種是把含有x的整個棧放到含有y的整個棧上面。另外一種是問x下面有多少個物品。

物品數目是30,000以內,操作次數在100,000以內。

一開始的時候我們想的是直接模擬?這個毫無疑問是不可以的。

但是一眼看過去,似乎和並查集沒什麼關係?

這個時候,我們從棧開始分析。計算乙個物品下面有多少個物品,那麼有兩種計算方法:

直接計算。

棧裡面的元素個數-當前距離棧頂的距離。

我們在這裡考慮算下面的個數?有沒有什麼好辦法?(反正我不會)

我在做這個題目的時候用的是第二種方法。

如果我們依舊是乙個棧的話,看成是乙個退化成鏈的樹,那麼當前結點距離棧頂的距離很容易就能看明白就是樹的深度。

(重點來了)

對於操作,我們看到修改操作是把兩個子樹合併到一起。

所以子樹的結點對於子樹的根節點的相對距離是不變的。

所以這條鏈像並查集那樣壓縮也是可以的(只不過壓縮路徑之後,距離不改變)。

那麼合併是怎麼做的呢?我們假設子樹a,b。 現在把a放到b上面。

那麼實際上就是a成為了子樹b的根。按照更新,子樹b上面的點記錄的距離要全部加上a原來的大小。

因為點是亂疊來疊去的,所以區間更新搞不了了。怎麼辦?

這個時候並查集的作用來了。只需要在b的根節點上面加上a的大小就行了。

為什麼?

因為b的結點都是指向b的根節點,一旦詢問b上面的結點的話,從b開始往上找一下根節點,在路徑壓縮的過程中把距離給加上去就好了。

舉個例子,a的大小為5,根節點為a,b的根節點b,b上面有乙個點x,x距離b的根節點是deep【x】。 那麼我們本來是x->b->a

其中x到b的深度為deep【x】,b到a的深度為5,那麼我們找爸爸的時候 路徑變成了x->a,b->a 此時deep[x]=5+deep[x];當然如果是有很多個原來是根節點的話,就由大家一起腦補了,實際上遞迴從上開始更新就好了。

**如下:

#include

#include

#include

using

namespace

std;

#define maxn 30000

int cnt[maxn+10];

int dep[maxn+10];

int fa[maxn+10];

void init(int n)

}int findfa(int x,int &cou)

fa[x]=findfa(fa[x],cou);

dep[x]=dep[x]+cou;

cou=dep[x];

return fa[x];

}int main()

else

}return

0;}

poj1988 帶權並查集

帶權並查集的應用 題意 說是有n塊磚,編號從1到n,有兩種操作,第一是把含有x編號的那一堆磚放到含有編號y的那一堆磚的上面 第二是查詢編號為x的磚的下面有多少塊磚。思路 帶權並查集,用dis i 表示元素i下邊有多少個元素,num i 表示元素i所在堆的磚塊總數 或者說dis i 當前元素到樹根的距...

POJ 1988 帶權並查集

題意 傳送門 poj 1988 題解堆的合併用帶權並查集維護。對於每乙個節點 i ii,維護以此節點為根節點 堆底 的堆的元素數量 sz i sz i sz i 以及此節點到其根節點的高度 h i h i h i 設 chi ld child chil d 為合併操作的 x xx 所在集合的根節點,...

POJ1988(帶權並查集,搬磚塊)

題意 可以這樣理解,有n快方形積木,一開始都是單獨的放到哪,然後有兩種操作 1 m a b 把a所在的那一堆落到b所在那一堆的上面 一開始自己是一堆 2 c a 問a下面有多少個積木 思路 感覺很久以前杭電上見過這個題目,比較簡單的帶權並查集,我們可以維護兩個權來滿足要求,第乙個就是記錄集合元素個數...