poj 1182 食物链 经典带权并查集(待补)
动物王国中有三类动物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),输出假话的总数。
tags:老早就想补这个题了,一直拖着。。
(1)每个点拆成三个点,偏移一下,写法简单一点
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<bitset> #include<vector> #include<set> #include<list> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 50005; int n, k, fa[N*3]; int Find(int x) {return fa[x]==x ? x : fa[x]=Find(fa[x]); } bool same(int a, int b) {return Find(a)==Find(b); } void Unite(int a, int b) { int faa=Find(a), fab=Find(b); if(faa!=fab) fa[faa]=fab; } int main() { scanf("%d %d", &n, &k); rep(i,1,n*3) fa[i]=i; int d, x, y, ans=0; while(k--) { scanf("%d %d %d", &d, &x, &y); if(x>n || y>n) { ++ans; continue; } if(d==1) { if(same(x,y+n) || same(x,y+2*n)) ++ans; else { Unite(x, y); Unite(x+n, y+n); Unite(x+2*n, y+2*n); } } else { if(x==y || same(x,y) || same(x,y+2*n)) ++ans; else { Unite(x, y+n); Unite(x+n, y+2*n); Unite(x+2*n, y); } } } printf("%d\n", ans); return 0; }
(2)还有一种写法,没时间搞了,待补