1. 程式人生 > >poj食物鏈,經典帶權並查集

poj食物鏈,經典帶權並查集

題目描述

動物王國中有三類動物 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;
}