题意:"1 X Y",表示X和Y是同类;"2 X Y",表示X吃Y;输入N(1 <= N <= 50,000),(0 <= K <= 100,000)表示最多有N个动物,同时有K句话。
如果当前的话与前面的话不矛盾就说当前的话是正确的;(无罪判定)问这K句话中有几句是假话;
思路:很裸的种类并查集,只是里面穿插了三种关系,即同类,A吃B,B吃A;其实看了数组的范围[3*N]和x+N,x+2*N就知道思路了;即x吃x+N;类推
对于判定是否是同类时,不要直接求解,因为这与初始化违背;这是利用无罪假设,不冲突即可,即x不与y+N,y+2*N同类即可合并x和y;
同理判断x是否吃y,不要直接判断x是否与y+2*n在同一个集合中,而是看反面是否成立;每次处理合并三种关系即可;
ps:千万别开始就陷入思维定式,认为要将每种同类弄成0,1,2然后0吃1..这种,因为这种初始化很难,并且对于开始输入很多同类时,不知道给这些同类赋几;
Memory: 1280K Time: 297MS #include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define MS0(a) memset(a,0,sizeof(a)) #define MS1(a) memset(a,-1,sizeof(a)) const int MAXN = 50050; int f[MAXN*3]; int Find(int a) { return a==f[a]?f[a]:f[a]=Find(f[a]); } bool sample(int a,int b) { return Find(a) == Find(b); } void _union(int a,int b) { a = Find(a),b = Find(b); f[a] = b; } int main() { int n,m; scanf("%d%d",&n,&m); int tot = 3*n,ans = 0; rep1(i,0,tot) f[i] = i; rep1(i,1,m){ int D,x,y; scanf("%d%d%d",&D,&x,&y); if(x > n || y > n) ans++; else{ if(D&1){ if(sample(x+n,y) || sample(x+n+n,y)) ans++; else{ _union(x,y); _union(x+n,y+n); _union(x+n+n,y+n+n); } } else{ if(sample(x,y) || sample(x+n+n,y)) ans++; else{ _union(x+n,y); _union(x+n+n,y+n); _union(x,y+n+n); } } } } printf("%d\n",ans); return 0; }
时间: 2024-12-22 03:41:50