poj食物鏈,經典帶權並查集
阿新 • • 發佈:2019-02-20
題目描述
動物王國中有三類動物 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 句話,輸出假話的總數。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <cmath> #include <cstdlib> #include <vector> #include <queue> #include <set> #include <map> using namespace std; typedef long long ll; const int maxn=1e5+10; int fa[maxn],rnk[maxn];//rnk點與根的關係 int n,k; void init(int x){ for(int a=0;a<=x;a++){ fa[a]=a; rnk[a]=0; } } int findfa(int x){ if(fa[x]==x) return x; else{ int mid=fa[x]; fa[x]=findfa(fa[x]);//壓縮 rnk[x]=(rnk[x]+rnk[mid])%3;//節點與根的關係 rnk[mid]是mid與根結點的關係 return fa[x];//第二個rnk[x]是當前的點到壓縮前的根的關係,rnk【mid】是之前的根到當前的根的關係,兩者相加即為當前的點到當前的根的關係 } } void merge(int r,int x,int y){ int fx=findfa(x); int fy=findfa(y); if(fx!=fy){ fa[fx]=fy; rnk[fx]=(rnk[y]-rnk[x]+r+3)%3; } } bool check(int a,int b,int c){ if (b>n||c>n||b<1||c<1) { return false; } if(a==1&&b==c) return false; int fb=findfa(b); int fc=findfa(c); if(fb==fc) return a==(rnk[b]-rnk[c]%3+3)%3; else return true; } int main() { int ans = 0; scanf("%d %d",&n,&k); init(n); for (int a=0; a<k; a++) { int o,p,q; cin>>o>>p>>q; o--; if(check(o,p,q)) merge(o,p,q); else ans++; } printf("%d\n",ans); return 0; }