猴子大王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 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 their 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.
在一个森林里住着N(N<=100000)只猴子。在一开始,他们是互不认识的。但是随着时间的推移,猴子们少不了争斗,但那只会发生在互不认识(认识具有传递性)的两只猴子之间。争斗时,两只猴子都会请出他认识的猴子里最强壮的一只(有可能是他自己)进行争斗。争斗后,这两只猴子就互相认识。 

每个猴子有一个强壮值,但是被请出来的那两只猴子进行争斗后,他们的强壮值都会减半(例如10会减为5,5会减为2)。 

现给出每个猴子的初始强壮值,给出M次争斗,如果争斗的两只猴子不认识,那么输出争斗后两只猴子的认识的猴子里最强壮的猴子的强壮值,否则输出 -1。

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.
第一行, 一个整数N,表示猴子的数量 
接下来N行,表示猴子的强壮值(<=32767) 
接下来一行,一个整数M(M<=100,000)表示与M次争斗。 
接下来M行,每行两个整数X和Y,表示在编号X和编号Y的猴子间发生了争斗。

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.
共M行,每行表示一次争斗的结果。如果争斗的两只猴子不认识,那么输出争斗后两只猴子的认识的猴子里最强壮的猴子的强壮值,否则输出 -1。

Sample Input

5
20
16
10
10
4
5
2 3
3 4
3 5
4 5
1 5

Sample Output

8
5
5
-1
10

Source

xinyue---ZOJ 2334
 
 
左偏树的模板,注意题目说的是打完架之后认识的最大值,不是那两只猴子!
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int N=100003;
 5 struct node{
 6     int w,l,r,fa,d;
 7 }t[N];
 8 int find(int x){
 9     return x==t[x].fa?x:t[x].fa=find(t[x].fa);
10 }
11 int merge(int x,int y){//合并 
12     if(!x||!y)return x+y;//有一个是空的树就直接返回另一个编号 
13     if(t[x].w<t[y].w)swap(x,y);//由于维护的是大根堆所以左边比右边小要进行交换 
14     t[x].r=merge(t[x].r,y);//右子树的根就是合并过后的编号 
15     if(!t[x].l||t[t[x].l].d<t[t[x].r].d)swap(t[x].l,t[x].r);//如果左边根本就没有树或者是左边的路径长小于右边就要交换 
16     t[x].d=t[t[x].l].d+t[t[x].r].d+1;//更新右子树路径的长度 
17     return x;//返回新结合的根节点 
18 }
19 int del(int x){
20     int root=merge(t[x].l,t[x].r);
21     t[x].l=t[x].r=0;
22     return root;
23 }
24 int main ()
25 {
26     int n;cin>>n;
27     for(int i=1;i<=n;i++){
28         scanf("%d",&t[i].w);
29         t[i].fa=i;
30     }
31     cin>>n;
32     while(n--){
33         int x,y;
34         scanf("%d%d",&x,&y);
35         x=find(x),y=find(y);//找出里面根,与维护并查集是一个道理 
36         if(x==y){
37             printf("-1\n"); continue;
38         }
39         //printf("%d\n",max(t[x].w,t[y].w)/2);
40         int a=del(x),b=del(y);//删除这两个代表性的值 
41         t[x].w>>=1, t[y].w>>=1;//这两个猴子打完架之后除以2 
42         int root=merge(a,b);//链接a,b 
43         root=merge(root,x); root=merge(root,y);//合并一下树 
44         t[x].fa=t[y].fa=t[root].fa=root;//更新他们的根节点的值 
45         printf("%d\n",t[root].w);
46     }
47     return 0;
48 }

over

猜你喜欢

转载自www.cnblogs.com/saionjisekai/p/9715222.html