hdu1512 Monkey King

hdu1512 Monkey King 解题报告

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4219    Accepted Submission(s): 1843


Problem 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 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.
 

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

题目大意

       有N(N<=100,000)只猴子,每只都有一个力量值.开始的时候互不认识,它们之间会发生M(M<=100,000)次斗争.每次发生a, b的斗争时, a, b都会从各自的朋友圈里拉出一个最强的,之后两只猴子打,打完后这两只猴子的力量值各减半.并且打完后,两只猴子的朋 友圈的所有人都互相认识(也就是不会再打).
       你的任务就是对于每个斗争,a, b是朋友,那么输出-1,否则输出打完后它们的朋友圈的最强猴子的力量值.
 

分析

      可以用任何一种可并堆解决这道题,我这里用的是左偏树。

      左偏树的性质:

             1、左偏树是堆

             2、dist[i]是i点到其儿子中最近的外节点的距离,左偏树满足所有节点i都有dist[lch]>=dist[rch]

      左偏树的操作:

            1、合并操作merge(a,b):

                   ①如果a或b是空节点,返回非空节点(也可能a和b都是空节点,返回其中一个空节点)

                   ②如果a的权值大于b的权值,则交换a和b(小顶堆)

                   ③执行merge(a->r,b)

                   ④如果a的左子树的dist小于右子树的dist,交换左右子树

                   ⑤dist[a]←dist[a->r]+1

            2、删除堆顶元素delete(a):a->l←a->r←a->f←NULL,令p=merge(a->l,a->r),用p代替a的位置

            3、插入一个元素insert(x):直接将x建成一棵只有一个节点的树,然后merge

            4、将n个点建成一棵左偏树:

                   算法一:n次insert,时间复杂度O(nlogn)

                   算法二:将n个节点建成n棵只有一个节点的左偏树,放进先进先出队列q,每次从q中取出前两棵左偏                                      树,进行merge操作,直到队列中只剩一棵树,可以证明时间复杂度为O(n)

            5、删除堆中任意一个节点x:首先merge(x->l,x->r)代替原来的x节点,然后执行update(x->f)

                   再删除操作后维护左偏树update(x):

                        ①如果dist[左子树]>dist[右子树],交换左右子树

                        ②更新dist:dist[x]=dist[x->r]+1

                        ③如果dist[x]发生了改变,则update(x->f)

      在这道题中,仅用到上述的1、2、3操作

代码

//hdu1512 monkey king 左偏树+并查集
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define maxn 100005
#define maxm 100005 
using namespace std;
int N, M;
struct NODE
{
	int v, d;
	NODE *l, *r, *ff;
	NODE(int vv){l=r=0;v=vv;d=0;}
}*hashh[maxn];
queue<NODE*> q;
NODE* find(NODE *x)
{return x->ff==x?x:(x->ff=find(x->ff));}
NODE* merge(NODE *a, NODE *b)
{
	if(!a||!b)return a?a:b;
	if(a->v < b->v)swap(a,b);
	b->ff=find(a);
	a->r=merge(a->r,b);
	int dl=a->l?a->l->d:-1, dr=a->r?a->r->d:-1;
	if(dl<dr)swap(a->l,a->r);
	a->d=dr+1;
	return a;
}
NODE* del(NODE *t)
{
	NODE *p=merge(t->l,t->r);
	if(p)p->ff=p;
	return p;
}
int fight(NODE *a, NODE *b)
{
	NODE *p1, *p2, *fa=find(a), *fb=find(b);
	if(fa==fb)return -1;
	p1=del(fa), p2=del(fb);
	fa->v>>=1,fb->v>>=1;
	fa->l=fa->r=fb->l=fb->r=0;fa->d=fb->d=0;
	p1=merge( merge(fa,p1) , merge(fb,p2) );
	return p1->v;
}
int main()
{
	int i, x, a, b;
	NODE *p1, *p2, *t; 
	while(scanf("%d",&N)!=EOF)
	{
		for(i=1;i<=N;i++)
		{
			scanf("%d",&x);
			p1=new NODE(x);
			p1->ff=p1;
			hashh[i]=p1;
		}
		scanf("%d",&M);
		for(i=1;i<=M;i++)
		{
			scanf("%d%d",&a,&b);
			printf("%d\n",fight(hashh[a],hashh[b]));
		}
	}
	return 0;
}


你可能感兴趣的:(hdu1512 Monkey King)