poj1182

链接:poj1182

Description

  • 动物王国中有三类动物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句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就
  • 是假话,否则就是真话。
  • 1)当前的话与前面的某些真的话冲突,就是假话;
  • 2)当前的话中X或Y比N大,就是假话;
  • 3)当前的话表示X吃X,就是假话。
  • 你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

    Input

  • 第一行是两个整数N和K,以一个空格分隔。
  • 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
  • 若D=1,则表示X和Y是同类。
  • 若D=2,则表示X吃Y。

    Output

  • 只有一个整数,表示假话的数目。

    Sample Input

    100 7
    1 101 1
    2 1 2
    2 2 3
    2 3 3
    1 1 3
    2 3 1
    1 5 5

    Sample Output

    3

    题解

  • 并查集高级操作,带权并查集
  • 用向量的方式算一下偏移量就好
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,x,y) for(register int i=x;i<=y;++i)
#define repd(i,x,y) for(register int i=x;i>=y;--i)
#define ll long long
using namespace std;
const int N=1e6+10;
int f[N],rl[N],n,m,op,x,y,ans;

int find(int x){
if(f[x]==x)return x;
int t=find(f[x]);
rl[x]=(rl[x]+rl[f[x]])%3;
return f[x]=t;
}

inline void un(int x,int y){
int a=find(x);
int b=find(y);
if(a==b){
if((3+rl[y]-rl[x])%3!=op)ans++;
return ;
}
f[b]=a;
rl[b]=(3+op+rl[x]-rl[y])%3;
}

int main(){
scanf("%d%d",&n,&m);
rep(i,1,n)f[i]=i;
rep(i,1,m){
scanf("%d%d%d",&op,&x,&y);
op--;
if(x>n||y>n||(op&&x==y)){ans++; continue;}
un(x,y);
}
printf("%d\n",ans);
return 0;
}