码迷,mamicode.com
首页 > 其他好文 > 详细

左偏树(p1456) 比较模板的一道题

时间:2019-10-23 23:49:47      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:ems   div   tin   const   scanf   print   标准   memset   val   

题意:有n只猴子,m个操作,每一个操作,会让这两堆猴子里的最大的两只打架,打完之后,自身权值减半,然后他们会成为朋友

也就是会属于同一棵树,细节:如果选出的猴子在同一堆,就输出-1,然后下一个操作,不用打架;

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<string.h>
 4 #include<math.h>
 5 using namespace std;
 6 const int maxn=1e5+10;
 7 int val[maxn];
 8 int f[maxn];
 9 int ch[maxn][2];
10 int dis[maxn];
11 int getf(int x)  //标准并查集
12 {
13     if(f[x]==x) return x;
14     else{
15         f[x]=getf(f[x]);
16         return f[x];
17     }
18 }
19 int Merge(int x,int y)
20 {
21     if(!x||!y) return x+y;  //到底了;
22     //保证最小堆性质     后面这个不懂
23     if(val[x]<val[y]) swap(x,y);
24     //这个大概就是创这个算法的人的习惯了,将其定在右子树。
25     //然后再在下面进行操作来满足偏左树的性质;
26     ch[x][1]=Merge(ch[x][1],y);
27     f[ch[x][1]]=x;   //并查集操作;
28     //满足偏左;
29     if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
30     //这个是偏左树的性质,想想就知道是对的。
31     dis[x]=dis[ch[x][1]]+1;
32     return x;
33 }
34 int main()
35 {
36     int n,m;
37     while(scanf("%d",&n)!=EOF){
38         memset(dis,0,sizeof(dis));
39         memset(ch,0,sizeof(ch));
40         for(int i=1;i<=n;i++){
41             scanf("%d",&val[i]);
42             f[i]=i;
43         }
44         scanf("%d",&m);
45         while(m--){
46             int t1,t2;
47             scanf("%d%d",&t1,&t2);
48             int u=getf(t1);
49             int v=getf(t2);
50             if(u==v){
51                 printf("-1\n");
52                 continue;
53             }
54             val[u]/=2;
55             int root=Merge(ch[u][1],ch[u][0]);
56             ch[u][1]=ch[u][0]=dis[u]=0;
57             int newx=Merge(root,u);
58             val[v]/=2;
59             root=Merge(ch[v][1],ch[v][0]);
60             ch[v][1]=ch[v][0]=dis[v]=0;
61             int newy=Merge(root,v);
62             root=Merge(newx,newy);   
63             f[newx]=f[newy]=root;   //这里两个点都要,其实只有一个点需要,
64             //因为只有一个点的父节点没有从已经被减半的根节点那更新回来。
65             //需要更新的点是根节点;
66             printf("%d\n",val[root]);
67         }
68     }
69     return 0;
70 }

 

左偏树(p1456) 比较模板的一道题

标签:ems   div   tin   const   scanf   print   标准   memset   val   

原文地址:https://www.cnblogs.com/pangbi/p/11729794.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!