Monkey King

题目

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只互不认识的猴子,都有自己的武力值,在后面的m天中,每天都有两只猴子打架,但是他们会叫上朋友帮忙,双方都会出战最强战力(朋友和自己里面的),如果这两只猴子是朋友,那么不需要打架,输出-1,否则打完之后武力值最强的都减半(战斗损失),并且这两个团体成为朋友(即两只猴子和他们的朋友都彼此认识了),输出新的团体中最强武力值~
解题思路:首先两只猴子要判断是否是朋友,以及打完之后要成为朋友,很容易想到并查集,通过并查集即可判断,然后就是两个猴子打架要知道最强武力值,可以联立并查集,将已经成为朋友的猴子按照武力值建一个最大堆,然后两个最大堆拿出堆顶,减半,然后都再插入,合并两个堆,输出堆顶.(思路很明显了!!!),难点在于合并撒,所以堆的合并我们还是用左偏树即可~

代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=100005;
int f[N],a[N],rs[N],ls[N],dis[N];
int find(int x){if (f[x]!=x) f[x]=find(f[x]);return f[x];}//找到父亲结点
int merge(int x,int y)//合并堆的操作
{
    if (!x || !y) return x+y;
    if (a[x]<a[y]) swap(x,y);
    rs[x]=merge(rs[x],y);
    if (dis[rs[x]]>dis[ls[x]]) swap(ls[x],rs[x]);
    dis[x]=dis[rs[x]]+1;
    return x;//返回堆顶
}
int pop(int x)//删除堆顶的操作,返回新的根节点
{
    f[x]=merge(ls[x],rs[x]);
    ls[x]=rs[x]=dis[x]=0;//记得初始化原来的根节点,后面要重新插入
    return f[x];
}
int main()
{
    int n,m;
    while (scanf("%d",&n)!=EOF)
    {
        memset(rs,0,sizeof(rs));memset(ls,0,sizeof(ls));
        memset(dis,0,sizeof(dis));
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=i;
        scanf("%d",&m);
        while (m--)
        {
            int x,y;scanf("%d%d",&x,&y);
            x=find(x); y=find(y); int top;//找到父亲结点,其实也就是最大堆的根节点
            if (x==y) {printf("-1\n");continue;}//如果都为一个父亲,那么输出-1
            a[x]/=2; int fx=pop(x); top=merge(x,fx); //第一个删除,减半,合并
            a[y]/=2; int fy=pop(y); top=merge(top,fy);//第二个
            top=merge(top,y); f[x]=f[y]=f[top]=top; //这一步最关键,让堆顶成为父亲
            printf("%d\n",a[top]);//每次输出堆顶的值
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值