種類並查集 帶權並查集

2021-09-25 22:56:31 字數 2896 閱讀 7103

p2024 (noi2001)食物鏈

題目描述

動物王國中有三類動物 a,b,c,這三類動物的食物鏈構成了有趣的環形。a 吃 b,b

吃 c,c 吃 a。

現有 n 個動物,以 1 - n 編號。每個動物都是 a,b,c 中的一種,但是我們並不知道

它到底是哪一種。

有人用兩種說法對這 n 個動物所構成的食物鏈關係進行描述:

第一種說法是「1 x y」,表示 x 和 y 是同類。

第二種說法是「2 x y」,表示 x 吃 y 。

此人對 n 個動物,用上述兩種說法,一句接一句地說出 k 句話,這 k 句話有的是真

的,有的是假的。當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。

• 當前的話與前面的某些真的話衝突,就是假話

• 當前的話中 x 或 y 比 n 大,就是假話

• 當前的話表示 x 吃 x,就是假話

你的任務是根據給定的 n 和 k 句話,輸出假話的總數。

輸入格式

從 eat.in 中輸入資料

第一行兩個整數,n,k,表示有 n 個動物,k 句話。

第二行開始每行一句話(按照題目要求,見樣例)

輸出格式

輸出到 eat.out 中

一行,乙個整數,表示假話的總數。

輸入輸出樣例

輸入 #1 複製

100 7

1 101 1

2 1 2

2 2 3

2 3 3

1 1 3

2 3 1

1 5 5

輸出 #1 複製

3說明/提示

1 ≤ n ≤ 5 ∗ 10^4

1 ≤ k ≤ 10^5

種類並查集的意義

並查集能維護連通性、傳遞性,通俗地說,親戚的親戚是親戚。

然而當我們需要維護一些對立關係,比如 敵人的敵人是朋友 時,正常的並查集就很難滿足我們的需求。

這時,種類並查集就誕生了。

常見的做法是將原並查集擴大一倍規模,並劃分為兩個種類。

在同個種類的並查集中合併,和原始的並查集沒什麼區別,仍然表達他們是朋友這個含義。

考慮在不同種類的並查集中合併的意義,其實就表達 他們是敵人 這個含義了。

按照並查集美妙的 傳遞性,我們就能具體知道某兩個元素到底是 敵人 還是 朋友 了。

種類並查集思路

就是用3倍的並查積的存各種動物的關係

一倍存本身,二倍存獵物,三倍存天敵

唯一容易忽略的點就是:自己的獵物的獵物 就是自己的天敵

那麼我們每次只要維護三個並查積的關係就可以了

種類並查集題解

#includeusing namespace std;

const int maxn=2e5+10;

int fa[maxn];

int n,k,opt,x,y;

int read() //讀入優化

while(ch>='0'&&ch<='9')

return n;

}int find(int x) //查詢

return x;

}int main()

if(opt==1)

//如果1是2的天敵或獵物,顯然為謊言

fa[find(x)]=find(y);

fa[find(x+n)]=find(y+n);

fa[find(x+2*n)]=find(y+2*n);

//如果為真,那麼1的同類和2的同類,1的獵物是2的獵物,1的天敵是2的天敵

} if(opt==2)

//如果1是2的同類或獵物,顯然為謊言

fa[find(x)]=find(y+2*n);

fa[find(x+n)]=find(y);

fa[find(x+2*n)]=find(y+n);

//如果為真,那麼1的同類是2的天敵,1的獵物是2的同類,1的天敵是2的獵物

} }cout<帶權並查集的意義

上網大概搜了下,對帶權並查集的詮釋是這樣的:

在對並查集進行路徑壓縮和合併操作時,這些權值具有一定屬性,即可將他們與父節點的關係,變化為與所在樹的根結點關係。

也就是說,權值代表著當前節點與父節點的某種關係(即使路徑壓縮了也是這樣),通過兩者關係,也可以將同一棵樹下兩個節點的關係表示出來。

帶權並查集思路

由題意得,動物一共只有a,b,c三種,也就是說只要確定了一種動物的種類和他們的關係(即權值),其他的動物的種類也就知道了。

我們用re陣列表示編號i與父親節點的權值關係,由於只有三種動物,所以權值也只有三種:0–>同種動物,1–>捕食關係,2–>**食關係,轉移時便可以採用對3取模來實現。(初始化為0,即自己與自己為同種動物)

帶權並查集題解

#include#includeusing namespace std;

const int maxn=2e5+10;

int fa[maxn],d[maxn]; //0-->同種動物,1-->捕食關係,2-->**食關係。

int read()

return n;

} int find(int x)

int f=find(fa[x]);

d[x]=(d[x]+d[fa[x]])%3;

fa[x]=f;

return f; }

int main()

if(opt==1)

else if(f_x!=f_y)

} if(opt==2)

else if(f_x!=f_y)}}

cout<}

帶權並查集種類並查集

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

並查集,帶權並查集

題意 ignatius過生日,客人來到,他想知道他需要準備多少張桌子。然而一張桌子上面只能坐上相互熟悉的人,其中熟悉可定義成為a與b認識,b與c認識,我們就說a,b,c相互熟悉 例如a與b熟悉and b與c熟悉,d與e熟悉,此時至少需要兩張桌子。輸入 t表示樣例個數,n表示朋友個數,朋友從1到n編號...

並查集 帶權並查集 種類並查集 入門基礎題

include include include include include include include includetypedef long long ll using namespace std const int inf 0x3f3f3f3f const int maxn 2e5 10...