帶權並查集之區間統計類和種類並查集

2021-08-22 13:21:58 字數 2500 閱讀 6489

我們都知道普通並查集可以理解為檢視集合間的關係和集合間的合併。

帶權並查集不僅記錄集合間關係,還記錄集合內元素間的關係(元素間連線的權值)。帶權並查集主要分為兩類:區間統計類和種類並查集

例題.hdu 3038 how many answers are wrong

題意:

給你一系列區間和,判斷給出的區間和中有幾個是不合法的。

題解:

1.如何建立區間之間的聯絡

2.如何發現悖論

1.如何建立聯絡

首先理解字母含義:

1.fx是x的祖先,fy是y的祖先,val[x]表示x到祖先的區間和(即[fx, x]),val[y]表示y到祖先的區間和(即[fy, y]),w表示y到x的區間和(即[x, y])。

重點來了,我們需要將所有區間和都視為向量,通過向量加減來判斷是否存在悖論

然後分類討論

[x,y]之間的和是可以求出的。 區間[x,y]的和就是可以寫成val[x] - val[y]。判斷給出的w與向量法計算的區間和是否相等就可以判斷是否是悖論。

建立新的區間關係,val[fy]表示兩個區間間(val[y]和val[x])的權值差(即fy與fx的區間和[fx,fy])。首先將fy指向fx,這代表fx是區間的左端點;fy->fx = fy->y +y->x + x->fx;因此val[fy] = val[x] - val[y] + w

重點講完了~

接下來就是一些細節了,比如在更新區間的時候要進行路徑的壓縮,壓縮的過程中需要對權值進行更新,目的是使每個已知區間最大化。

//帶權並查集 更新父節點的同時更新權值

#include

using

namespace

std;

const

int n = 200020;

int pre[n];

int cnt[n];//cnt[i]代表i到自己祖先的權值

int find(int x)

return pre[x];

}int main()

while(m--)

/*在合併操作中,對我們需要更新cnt[fb](由於fy成為fa的子節點),公式:cnt[fy] = cnt[x - 1] - cnt[y] + w

- 更新cnt[fy]的目的是維護子樹(fy)相對於父親樹(fx)之間的權值差。

- cnt[y]儲存結點y到結點fy之間的權值; cnt[x-1]儲存結點x-1到結點fx之間的權值;w是結點x-1到結點y之間的權值

- 所以cnt[fy]的值=從結點fa到結點x-1的權值(+cnt[x - 1]),加上從結點x到結點y的權值(+w),最後減去結點fy到結點y的權值(-cnt[y])

*/else

}printf("%d\n", s);

}return

0;}

注意:權值的累加變成累加結果%mod ,,,例題:poj 1182 食物鏈

題意:

給出n個動物所構成的食物鏈關係;n個動物分為三類:a,b,c,這三類動物的食物鏈構成了有趣的環形,a吃b, b吃c,c吃a

有幾個種類就模幾,這裡是%3

r[x] 表示x與祖先的關係

這裡有三種關係:

r[x] = 0 表示x與祖先fx同類

r[x] = 1 表示x吃祖先fx

r[x] = 2 表示x被祖先fx吃

剩下的也是用向量來解決~

#include

#include

using

namespace

std;

const

int n = 100000+10;

int pre[n], r[n];

int find(int x)

return pre[x];

}int main()

while(m--)

else

if(fx == fy && (r[x] - r[y] + 3)%3 != d-1)

else

if(fx != fy)

}printf("%d\n", s);

return

0;}

帶權並查集種類並查集

帶權並查集 種類並查集 例題 種類並查集 洛谷 p2024 食物鏈 與普通並查集不同是新增加屬性 group i group i 表示它和fa i 的關係,對於這三種種類,同類可以用 0表示,其他兩種分別用 1表示該結點被父節點吃,2表示該節點吃父節點。舉個例子 現在有 pa 3 4 group 3...

種類並查集 帶權並查集

p2024 noi2001 食物鏈 題目描述 動物王國中有三類動物 a,b,c,這三類動物的食物鏈構成了有趣的環形。a 吃 b,b 吃 c,c 吃 a。現有 n 個動物,以 1 n 編號。每個動物都是 a,b,c 中的一種,但是我們並不知道 它到底是哪一種。有人用兩種說法對這 n 個動物所構成的食物...

並查集和帶權並查集

並查集是乙個很高效演算法,理解起來也很簡單,寫起來更簡單。fat i i 找到乙個點的祖先 int findfat int x 二中的方法肯定不好,因為如果資料比較極端,那麼並查集就退化成乙個鏈了 如果加入了路徑壓縮,並查集這個演算法就更高效了。int findfat int x 遞迴寫法 int ...