标签:子节点 编号 algo bool 路径压缩 inpu ace typedef 一个
Input
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
题解:
首先我们要明确并查集的作用:快速判断两个数是否同一集合与快速合并两个集合成一个集合并求出一些节点之间的关系,
根据的就是树的特点:每个孩子节点有且仅有一个父节点。这样就用数组记录父节点就还(根就记录自己),合并操作就是合并
两个根节点,这儿有个优化就是启发式合并:根记录孩子个数,并把个数少的并到个数大的上面。
不过我们有其他大招:路径压缩,即我们每次查询的时候都把一条线上的所有节点连接到祖先节点,这样每次查找都很快
(并查集在路径压缩之后的时间复杂度是阿克曼函数)。依据就是我们只需要知道多个孩子节点的祖先是否一致就能判断是否
一个集合,不需要知道树上的结构。我们的权值则是一般记录此节点与父节点的关系,只要满足这个关系可以传递我们就可以模仿矢量计算来处理权值。
这儿我们要明确是有三种关系的:两者同类,吃父节点,被父节点吃,所以权值可以用0,1,2表示
注意有个关键就是当我们知道x与祖先x1的关系,y与祖先y1的关系,x与y的关系时,求x1与y1的关系时,使用矢量 计算:
x1->x ->y ->y1 计算
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <vector> 6 #include <cstdlib> 7 #include <iomanip> 8 #include <cmath> 9 #include <ctime> 10 #include <map> 11 #include <set> 12 #include <queue> 13 using namespace std; 14 #define lowbit(x) (x&(-x)) 15 #define max(x,y) (x>y?x:y) 16 #define min(x,y) (x<y?x:y) 17 #define MAX 100000000000000000 18 #define MOD 1000000007 19 #define pi acos(-1.0) 20 #define ei exp(1) 21 #define PI 3.141592653589793238462 22 #define INF 0x3f3f3f3f3f 23 #define mem(a) (memset(a,0,sizeof(a))) 24 typedef long long ll; 25 ll gcd(ll a,ll b){ 26 return b?gcd(b,a%b):a; 27 } 28 bool cmp(int x,int y) 29 { 30 return x>y; 31 } 32 /*n个动物 k句话 有一种循环a吃b 吃c c吃a 开始不知道n种动物关系是什么 33 两种询问:d=1 x y为同类 d=2 x吃y 判断假话条数(关键之违背之前的关系) 34 并查集可以很好解决的满足区间传递关系的区间合并问题,注意一般是多棵树*/ 35 const int N=50005; 36 const int mod=1e9+7; 37 int fat[N],ran[N]; 38 void Init(int n)//初始化重要 39 { 40 for(int i=0; i<=n; i++){ 41 fat[i]=i;//初始化都是指向(看做)自己 42 ran[i]=0;//0同类 1吃父节点 2被父节点吃 43 } 44 return; 45 } 46 int Find(int x)//找寻父节点+路径压缩 47 { 48 if(x==fat[x]) 49 return fat[x]; 50 int y=Find(fat[x]); 51 ran[x]=(ran[x]+ran[fat[x]])%3;//递归后从祖先节点向后到每个孩子来计算 52 return fat[x]=y;//路径压缩 53 } 54 int Union(int typ,int x,int y)//区间并与查询 55 { 56 int x1=Find(x); 57 int y1=Find(y); 58 if(x1==y1){//共父节点才能判断出关系 59 if((ran[x]-ran[y]+3)%3==typ-1) 60 return 0; 61 return 1; 62 } 63 fat[x1]=y1;//连接两父节点 64 ran[x1]=(-ran[x]+typ-1+ran[y]+3)%3;//使用类似向量方法来计算权值,虽然题目只有两个,但是会出现被吃这种情况,所以要变成3种情况,注意一定要处理负数的情况 65 return 0; 66 } 67 int main() 68 { 69 int n,k,ans; 70 int typ,smt1,smt2; 71 scanf("%d %d",&n,&k); 72 Init(n); 73 ans=0; 74 for(int i=0;i<k; i++){ 75 scanf("%d %d %d",&typ,&smt1,&smt2); 76 if(smt1==smt2&&typ==2) 77 ans++; 78 else if(smt1>n||smt2>n) 79 ans++; 80 else 81 ans+=Union(typ,smt1,smt2); 82 } 83 printf("%d\n",ans); 84 return 0; 85 }
标签:子节点 编号 algo bool 路径压缩 inpu ace typedef 一个
原文地址:http://www.cnblogs.com/shixinzei/p/7278364.html