有点意思的并查集

Posted lmcc1108

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有点意思的并查集相关的知识,希望对你有一定的参考价值。

K - How Many Answers Are Wrong HDU - 3038

题目大意:两个人玩游戏,一个人说一个区间内的数的和,然后判断她说的有多少句和之前说过的冲突的。

一开始想的用一个数就代表他到根节点里的数和,但是在路径压缩时明显不对,因为已知[1,8],[8,10]并不能推出[1,10],但如果是(1,8],(8,10]就可以推出(1,10]。所以关键在于一个左开右闭的区间。

 1 #include<stdio.h>
 2 struct Extent{
 3     int gen,sum;//sum为区间(gen,x]内的和 
 4 }E[201108];
 5 int gui(int x);
 6 int bing(int x,int y,int z);
 7 int main()
 8 {
 9     int n,m,i;
10     while(scanf("%d%d",&n,&m)!=EOF)
11     {
12         for(i=0;i<=n;i++)
13         {
14             E[i].gen=i;
15             E[i].sum=0;//一开始为空集即0 
16         }
17         int x,y,z,ans=0;
18         while(m--)
19         {
20             scanf("%d%d%d",&x,&y,&z);
21             ans+=bing(x-1,y,z);//每次给的是[x,y]的值,所以归并时是将x-1和y归并 
22         }
23         printf("%d
",ans);
24     }
25     return 0;
26 }
27 int gui(int x)
28 {
29     if(E[x].gen==x)
30         return x;
31     int y=E[x].gen,z=gui(E[x].gen);//先回溯更新父节点和根节点的权
32     E[x].sum=E[y].sum+E[x].sum;//(a,b]和为sum1 (b,c]和为sum2 则(a,c]为sum1+sum2 
33     return E[x].gen=z;
34 }
35 int bing(int x,int y,int z)
36 {
37     int bx=gui(x);
38     int by=gui(y);
39     if(bx==by)
40     {
41         if(E[y].sum-E[x].sum!=z)
42             return 1;
43     }
44     else
45     {
46         E[by].gen=bx;
47         E[by].sum=E[x].sum-E[y].sum+z;//向量加法 
48     }
49     return 0;
50 }

E - Peculiar apple-tree CodeForces - 931D

题目大意;有一颗苹果树,有很多花(??我英语不好),然后第一朵在树跟,其他在树枝,每次每朵花会一个结果,然后同时往下掉p的花中,掉到同一朵花的时,偶数个的苹果会全部碰碎,奇数个的只剩一个。问一个人在第一朵花能捡到的苹果数量。

画图来理解就是看他们最后能不能掉到第一朵花,而怎么处理同时掉落呢,距离。用它们到第一距离就可以代表时间了。注意距离不是高度,比如高度3的话苹果掉到1,高度7的话的苹果掉到3,那高度3 的话与第一朵花的距离是1,高度7与第一朵花的距离是2。这样,然后就是一个并查集。然后看它们到第一朵花的距离,相同的就会碰到一起。

 1 #include<stdio.h>
 2 #include<string.h>
 3 struct Apple{
 4     int gen,dis;//gen是这个苹果最后会掉到哪朵花 dis是这朵花到gen的距离 
 5 }A[101108];
 6 int book[101108];
 7 inline int gui(int x){
 8     if(A[x].gen==x)
 9         return x;
10     return A[x].gen=gui(A[x].gen);
11 }
12 int main()
13 {
14     int n,i,p;
15     scanf("%d",&n);
16     for(i=1;i<=n;i++)
17     {
18         A[i].gen=i;//一开始苹果结在这个花这里 
19         A[i].dis=0;//距离没得说就是0 
20     } 
21     for(i=2;i<=n;i++)
22     {
23         scanf("%d",&p);
24         A[gui(i)].gen=gui(p);//并查集,让它的gen为最后掉到的地方 
25         A[i].dis=A[p].dis+1;//而它到gen的距离就是它下一个掉落的地方的距离+1 
26     } 
27     memset(book,0,sizeof(book));
28     for(i=1;i<=n;i++)//从第一个苹果开始 
29         if(gui(i)==1)//如果能掉到第一朵花 
30             book[A[i].dis]++;
31     //因为苹果都是同时掉落,所有用距离来代表时间,如果到达gen的距离相同说明他们会碰到一起
32     //book就统计最终能到第一朵花的花的距离,看一下每个距离相同的有多少个
33     int ans=0;
34     for(i=0;i<n;i++)
35         ans+=book[i]%2;//最后对2取模,同时间如果有偶数个苹果碰到一起就全部销毁,奇数个只剩一个 
36     printf("%d
",ans);
37     return 0;
38 }

 

以上是关于有点意思的并查集的主要内容,如果未能解决你的问题,请参考以下文章

并查集-----好忧伤的并查集

带偏移量的并查集

并查集(入门)

每天刷个算法题20160522:支持各种类型的并查集

一道神奇的并查集

每天刷个算法题20160522:支持各种类型的并查集