题解 P1456 【Monkey King】

· · 题解

这一道题就是使用的正常的可并堆

可并堆就是可以合并的堆

在合并前后都可以保持堆的性质,可以是小根堆也可以是大根堆。

so

我们要使用一些神奇的数据结构来维护这些堆

目前可以维护可并堆的有:左偏树,斜堆……

其实还有很多我就不一一介绍了

今天我们来探讨一下左偏树

这道题题面意思是给每个猴子和他认识的人一起维护一个大根堆;

然后每一次修改就是将两个大根堆的堆顶取出,并将战斗力除以二,

插入合并的两个堆中;

所以我们需要维护左偏树。

int hebing (int a,int b)
{
    if(!a)return b;//如果有一个是空堆就返回
    if(!b)return a;
    if(key[a]<key[b])swap(a,b);//保持左偏树性质
    rc[a]=hebing(rc[a],b);//迭代向下合并
    if(date[rc[a]]>date[lc[a]])swap(lc[a],rc[a]);//继续维持性质
    date[a]=date[rc[a]]+1;//进行合并
    return a;//返回合并后的一共大小
}

这是左偏树的核心代码

十分明(通)了(俗)简(易)洁(懂);

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int lc[maxn],rc[maxn],date[maxn],key[maxn],fa[maxn];
int hebing (int a,int b)
{
    if(!a)return b;//如果有一个是空堆就返回
    if(!b)return a;
    if(key[a]<key[b])swap(a,b);//保持左偏树性质
    rc[a]=hebing(rc[a],b);//迭代向下合并
    if(date[rc[a]]>date[lc[a]])swap(lc[a],rc[a]);//继续维持性质
    date[a]=date[rc[a]]+1;//进行合并
    return a;//返回合并后的一共大小
}
int ff(int x)//寻找父亲
{
    return (fa[x]==x)?x:ff(fa[x]);
    /*
        相当于
        if(fa[x]!=x)return ff(fa[x]);
        else return x;
    */
}
inline int read(){//读入优化
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
void work(int a,int b)//根据题目来完成输出
{
    if((a=ff(a))==(b=ff(b)))//特判
    {
        cout<<"-1"<<endl;
        return ;
    }
    //合并
    //只要看懂核心代码就可以明白
    fa[b]=a;
    int art;
    int rt;
    int brt;
    key[a]>>=1;
    rt=hebing(lc[a],rc[a]);
    lc[a]=rc[a]=date[a]=0;
    art=hebing(a,rt);
    fa[rt]=fa[a]=art;
    key[b]>>=1;
    rt=hebing(lc[b],rc[b]);
    lc[b]=rc[b]=date[b]=0;
    brt=hebing(b,rt);
    fa[rt]=fa[b]=brt;
    rt=hebing(art,brt);
    fa[art]=fa[brt]=rt;
    printf("%d\n",key[rt]);
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {for(int i=1;i<=n;i++)
    {
        lc[i]=rc[i]=date[i]=0;
        fa[i]=i;
        key[i]=read();
    }
    int m=read();
    for(int i=1;i<=m;i++)
    {
        work(read(),read());
    }
    }
    return 0;
}

这道题就这样完成了

祝大家 AK IOI