第一次做種類並查集的問題
想了一會,發現其本質如下:
知得題目中的任意兩個變量之間的關係,然後根據關係建立並查集,並在尋找祖先的時候根據關係層層修改
有的時候種類並查集可以大大減少代碼量
動物王國中有三類動物 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 句話,輸出假話的總數。
輸入輸出格式
輸入格式:
第一行兩個整數,N,K,表示有 N 個動物,K 句話。
第二行開始每行一句話(按照題目要求,見樣例)
輸出格式:
solution
//種類並查集 #include<iostream> #include<cstdio> using namespace std; int fa[300866]; //同類關係1-n //a獵殺b a:1-n b:n-2n //a被b獵殺 a:1-n b:2n-3n int n,m,ans; int relation,u,v; int find(int u) { return fa[u] == u ? u : fa[u] = find(fa[u]); } void unionn(int u,int v) //將在u與v上的關係合併,就是說u和v是同類 { int fa_u = find(u); int fa_v = find(v); fa[fa_u] = fa_v; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n * 3;i++) fa[i] = i; while(m--) { scanf("%d%d%d",&relation,&u,&v); if(u > n || v > n) { ans++; continue; } if(relation == 1) //u和v是同類 { if(find(u + n) == find(v) || find(u + n + n) == find(v)) //可以推知不滿足 { ans++; continue; } else { unionn(u,v); unionn(u + n,v + n); unionn(u + n + n,v + n + n); } } if(relation == 2) //u捕食v { if(u == v || find(u) == find(v) || find(u + n + n) == find(v)) //可以推知不滿足 { ans++; continue; } else { unionn(u,v + n + n); //u與v的天敵是同類 unionn(u + n,v); unionn(u + n + n,v + n); } } } printf("%d",ans); return 0; }