hdu 1512 Monkey King 左偏树

题目链接:HDU - 1512

Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can‘t avoid quarrelling, and it only happens between two monkeys who does not know each other. And when it happens, both the two monkeys will invite the strongest friend of them, and duel. Of course, after the duel, the two monkeys and all of there friends knows each other, and the quarrel above will no longer happens between these monkeys even if they have ever conflicted.
Assume that every money has a strongness value, which will be reduced to only half of the original after a duel(that is, 10 will be reduced to 5 and 5 will be reduced to 2).
And we also assume that every monkey knows himself. That is, when he is the strongest one in all of his friends, he himself will go to duel.

Input

There are several test cases, and each case consists of two parts.
First part: The first line contains an integer N(N<=100,000), which indicates the number of monkeys. And then N lines follows. There is one number on each line, indicating the strongness value of ith monkey(<=32768).
Second part: The first line contains an integer M(M<=100,000), which indicates there are M conflicts happened. And then M lines follows, each line of which contains two integers x and y, indicating that there is a conflict between the Xth monkey and Yth.

Output

For each of the conflict, output -1 if the two monkeys know each other, otherwise output the strongness value of the strongest monkey in all friends of them after the duel.

题意描述:有n只猴子,每只猴子有一个值,两只猴子如果打架的话,他们的值各自掉一半。给出m个事件,每个事件给出两只猴子,如果两只猴子不认识的话,打完架就成为了朋友(两只猴子的各自朋友也都互相成为了朋友),求出打完架后两只猴子的所有朋友中值最大的。

算法分析:这道题我刚开始做的时候,想到了并查集,以为这就够了(其实时间复杂度我也不敢直视),交上去果断TLE了,后来看了讨论里有说,尼玛,这就是传说中的左偏树的题目啊,果断得好好学习一下,弥补一下自己的数据结构的知识。

说明:头一次搞左偏树,代码是借鉴别人的,不过真心写的比较好就拿来了。同时,推荐一下集训队的论文,基本上看了论文后就对左偏树有了一定的了解了。

左偏树的特点及其应用

 1 /*左偏树*/
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<algorithm>
 8 #define inf 0x7fffffff
 9 using namespace std;
10 const int maxn = 100000+10;
11
12 int father[maxn];
13 struct node
14 {
15     int l,r;
16     int dis;
17     int strong;
18 }LTree[maxn];
19 int Find(int x)
20 {
21     if (father[x]==x) return x;
22     return father[x]=Find(father[x]);
23 }
24 int Merge(int x,int y)
25 {   //返回合并后的根
26     if (x==0) return y;
27     if (y==0) return x;
28     if (LTree[x].strong < LTree[y].strong)            //大顶堆
29         swap(x,y);
30     LTree[x].r = Merge(LTree[x].r,y);            //递归合并右子树和Y
31     int l = LTree[x].l , r = LTree[x].r;
32     father[r] = x;                        //更新T右子树的根
33     if (LTree[l].dis < LTree[r].dis)                //维护堆性质
34         swap(LTree[x].l,LTree[x].r);
35     if (LTree[x].r == 0)                    //如果没有右子树 则距离为0
36         LTree[x].dis = 0;
37     else
38         LTree[x].dis = LTree[LTree[x].r].dis + 1;
39     return x;
40 }
41 int del(int x)
42 {   //返回删除根以后左右子树的合并的根
43     int l,r;
44     l=LTree[x].l;
45     r=LTree[x].r;
46     father[l]=l;
47     father[r]=r;
48     LTree[x].l=LTree[x].r=LTree[x].dis=0;
49     return Merge(l,r);
50 }
51 void solve(int x,int y)
52 {
53     LTree[x].strong /= 2;
54     LTree[y].strong /= 2;
55     //问每次PK以后,当前这个群体里力量最大的猴子的力量是多少。
56     int left,right;
57     left = del(x);
58     right = del(y);
59     left = Merge(left,x);
60     right = Merge(right,y);
61     left = Merge(left,right);
62     printf("%d\n",LTree[left].strong);
63 }
64 int main()
65 {
66     int n,m,x,y;
67     while (scanf("%d",&n)!=EOF)
68     {
69         for (int i=1 ;i<=n ;i++)
70         {
71             scanf("%d",&LTree[i].strong);
72             LTree[i].l=0;
73             LTree[i].r=0;
74             LTree[i].dis=0;
75             father[i]=i;            //起始已自己为父亲
76         }
77         scanf("%d",&m);
78         for (int i=1 ;i<=m ;i++)
79         {
80             scanf("%d%d",&x,&y);
81             int fx=Find(x),fy=Find(y);
82             if (fx == fy) printf("-1\n");
83             else solve(fx,fy);
84         }
85     }
86     return 0;
87 }
时间: 2024-08-26 14:24:15

hdu 1512 Monkey King 左偏树的相关文章

HDU 1512 Monkey King ——左偏树

[题目分析] 也是堆+并查集. 比起BZOJ 1455 来说,只是合并的方式麻烦了一点. WA了一天才看到是多组数据. 盲人OI (- ̄▽ ̄)- Best OI. 代码自带大常数,比启发式合并都慢 [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <

猴子大王Monkey King 左偏树+并查集维护

Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can't avoid quarrelling, and it only happens between two monkeys who does not know e

zoj 2334 Monkey King/左偏树+并查集

原题链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1389 大致题意:N只相互不认识的猴子(每只猴子有一个战斗力值) 两只不认识的猴子之间发生冲突,两只猴子会分别请出它们认识的最强壮的 猴子进行决斗.决斗之后这,两群猴子都相互认识了. 决斗的那两只猴子战斗力减半...有m组询问 输入a b表示猴子a和b发生了冲突,若a,b属于同一个集合输出-1 否则输出决斗之后这群猴子(已合并)中最强的战斗力值... 具体思路:用并查

ZOJ 2334 HDU 1512 Monkey King

题意: 猴子们打架  认识的猴子不会打架  两只猴子打完以后就认识了  A认识B B认识C A也认识C  每次打架由两伙猴子进行  分别选出自己的最高战斗力  在战斗之后两只猴子战斗力减半  给出m次打架  输出打架后这一伙猴子里的最强战斗力 思路: 判断两只猴子是不是一伙的  用到并查集 快速找出一伙猴子中的最强战斗力用到堆  但打完架两伙猴子合并时堆需要nlogn复杂度  因此用左偏树代替堆 代码: #include<cstdio> #include<cstring> #inc

HDU 1512 Monkey King

左偏树. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 100500 using namespace std; int root[maxn],ls[maxn],rs[maxn],val[maxn],father[maxn],n,m; int x,y,dis[maxn]; int find(

数据结构(左偏树):HDU 1512 Monkey King

Monkey King Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4714    Accepted Submission(s): 2032 Problem Description Once in a forest, there lived N aggressive monkeys. At the beginning, they e

Monkey King HDU - 1512 (左偏树)

Monkey King HDU - 1512 忽然看到左偏树,挺简单的,抄了个模板题练练 1 //左偏树 2 #include <bits/stdc++.h> 3 using namespace std; 4 const int maxn = 100010; 5 struct Node{ 6 int val, dis, l, r; 7 }p[maxn]; 8 int f[maxn]; 9 int gf(int x){ 10 return x == f[x] ? f[x] : f[x] = gf

HDU 1512 并查集+左偏树

Monkey King Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3105    Accepted Submission(s): 1330 Problem Description Once in a forest, there lived N aggressive monkeys. At the beginning, they e

zoj2334 Monkey King , 并查集,可并堆,左偏树

提交地址:点击打开链接 题意:  N(N<=10^5)只猴子,初始每只猴子为自己猴群的猴王,每只猴子有一个初始的力量值.这些猴子会有M次会面.每次两只猴子x,y会面,若x,y属于同一个猴群输出-1,否则将x,y所在猴群的猴王的力量值减半,然后合并这两个猴群.新猴群中力量值最高的为猴王.输出新猴王的力量值. 分析:涉及集合的查询,合并,取最值. 利用并查集和左偏树即可解决. #include <cstdio> #include <cstring> #include <io