洛谷 P1456Monkey King

题目描述

要把打架的两堆猴子合并为一堆,查询的又是最大值,所以很容易想到可并堆。

题目要求打完架后战斗力最大的猴子的战斗力要减半,但不能直接在堆中进行这个操作,因为战斗力减半后这只猴子不一定是战斗力最大的猴子了,所以要先把这只猴子从堆中删除,减半后再插入。

#include<complex>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+7;
int n,m;
int key[N],son[N][2],fat[N],dis[N];
int qread()
{
    int x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9')ch=getchar();
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int Merge(int A,int B)
{
    if(!A || !B)return A+B;
    if(key[A]<key[B] || (key[A]==key[B] && A>B))swap(A,B);
    son[A][1]=Merge(son[A][1],B);
    fat[son[A][1]]=A;
    if(dis[son[A][1]]>dis[son[A][0]])swap(son[A][1],son[A][0]);
    dis[A]=dis[son[A][1]]+1;
    return A;
}
int Top(int x)
{
    while(fat[x])x=fat[x];
    return x;
}
int Pop(int x)
{
    int l=son[x][0],r=son[x][1];
    fat[l]=fat[r]=0;
    son[x][0]=son[x][1]=dis[x]=0;
    return Merge(l,r);
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(dis,0,sizeof(dis));
        memset(son,0,sizeof(son));
        memset(fat,0,sizeof(fat));
        for(int i=1;i<=n;i++)
            key[i]=qread();
        scanf("%d",&m);
        int x,y,r1,r2;
        while(m--)
        {
            x=qread();y=qread();
            r1=Top(x);r2=Top(y);
            if(r1==r2)puts("-1");
            else
            {
                key[r1]>>=1;key[r2]>>=1;
                int l=Pop(r1),r=Pop(r2);
                l=Merge(l,r1);r=Merge(r,r2);
                printf("%d
",key[Merge(l,r)]);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LeTri/p/8667839.html