标签:img one out isp nta 有趣的 init 两种 结果
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5Sample Output
3
学习带权并查集。
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <map> #define Max 50005 using namespace std; int n,k,f[Max],tag[Max],c; ///f记录双亲结点 tag记录与双亲结点关系 0表示同类 1表示吃该结点 2表示被该结点吃 ///e.g. 1吃2 tag[1] = 0(初始和自己同类),tag[2] = 1;2吃3 tag[2] = 1,tag[3] = 1,getf之后 tag[3] = 2,因为3吃1;34同类 tag[3] = 2,tag[4] = 0,getf之后tag[4] = 2 ///现在tag[1] = 0,tag[2] = 1,tag[3] = 2,tag[4] = 2 ///此时判断 1吃2 (tag[2] - tag[1] + 3) % 3 = 1 满足;判断4吃2 (tag[2] - tag[4] + 3) % 3 = 2,结果是4被2吃 ///观察如果两个点x,y是同一个双亲,列举xy和双亲的关系 ///1.xy都被吃tag[x] = 1,tag[y] = 1,此时xy同类计算针对于x的tag‘[y]应该是 0 满足(tag[y] - tag[x] + 3) % 3 = 0 ///2.x被吃 被y吃 tag[x] = 1,tag[y] = 2,y被x吃,tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 1 (两个交换类似) ///3.x同类 被y吃 tag[x] = 0,tag[y] = 2,y吃x,tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 2 (两个交换类似) ///4.x同类 y被吃 tag[x] = 0,tag[y] = 1,y被x吃, tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 1 (两个交换类似) ///5.xy都同类显而易见 ///6.被xy都吃,xy也是同类的 void init() { for(int i = 1;i <= n;i ++) { f[i] = i;///初始双亲是自己 } } int getf(int a)///寻根压缩 { if(f[a] != a) { int t = getf(f[a]);///如果直接让f[a] = 根 下一步就没意义了,tag[根] = 0 tag[a] = (tag[a] + tag[f[a]]) % 3;///根据a和双亲的关系与双亲和根的关系 转化为a和根的关系(规律很容易发现) f[a] = t; } return f[a]; } int mer(int d,int a,int b)///d = 0 同类 d = 1 a吃b { int aa = getf(a); int bb = getf(b); if(aa == bb)///表示在同一条食物链中 { if((tag[b] - tag[a] + 3) % 3 != d)return 0; return 1; } tag[bb] = (tag[a] - tag[b] + 3 + d) % 3; f[bb] = aa; return 1; } int main() { int d,a,b; scanf("%d%d",&n,&k); init(); for(int i = 0;i < k;i ++) { scanf("%d%d%d",&d,&a,&b); if(a > n || b > n || !mer(d - 1,a,b))c ++;///超过范围是假话 与原话不符或者与事实不符 } printf("%d",c); }
标签:img one out isp nta 有趣的 init 两种 结果
原文地址:https://www.cnblogs.com/8023spz/p/8934365.html