【POJ-1182】解题报告(带权并查集)

原始题目

食物链

  • Time Limit: 1000MS
  • Memory Limit: 10000K
  • Total Submissions: 95522
  • Accepted: 28832

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

Source

Noi 01

题目大意

如题

解题思路

  • 不仅要储存集合的关系,且要表示集合间相互元素的关系,关系可合并(推导),考虑带权并查集
  • 维护一个relate数组,\(relate[i]\)表示i对根结点的关系。
    • 0:与根同类
    • 1:吃根
    • 2:被根吃
  • 推导规则(由于循环食物链,考虑模数关系):
    • A对B的关系为x,B对C的关系为y,则A对C的关系为\((x+y)%3\)
    • A对B的关系为x,A对C的关系为y,则B对C的关系为\((y-x+3)%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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <cmath>
#include <list>
using namespace std;

const int maxn=1e5+5;
const int maxm=1e5+5;


typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<string,string> pss;



#define rep(i,a,n) for(int i=a;i<n;++i)
#define per(i,a,n) for(int i=n-1;i>=a;--i)
#define fi first
#define se second
#define mp make_pair
#define np next_permutation
#define pb push_back
#define INF 0x3f3f3f3f
#define EPS 1e-8
#define cl(x,a) memset(x,a,sizeof(x))
#define all(x) x.bein(),x.end()

const int maxl=26;
int n,k,d,x,y;
int fa[maxn],relate[maxn];
void init(){
rep(i,0,maxn){
fa[i]=i;
relate[i]=0;
}
}

int find(int x){
if(fa[x]==x){
return x;
}
else {
int temp=fa[x];
fa[x]=find(fa[x]);
relate[x]=(relate[x]+relate[temp])%3;
return fa[x];
}
}

bool merge(int r, int x, int y){
int fx= find(x);
int fy=find(y);
if(fx==fy){
if((relate[x]-relate[y]+3)%3==d) return true;
else return false;

}
else{
fa[fx]=fy;
relate[fx]=(r+relate[y]-relate[x]+3)%3;
return true;
}
}

int main(){

scanf("%d%d",&n,&k);
init();
int a,b,c,ccnt=0;
rep(i,0,k){
scanf("%d%d%d",&d,&x,&y);
d--;
if(x>n || y>n ){
ccnt++;
continue;
}
if(d && x==y){
ccnt++;
continue;
}
if(merge(d,x,y)==false) ccnt++;
}
printf("%d\n",ccnt);
}

收获与反思

  • 并查集知识待补充。