【HDU1512/ZOJ2334】Monkey King-左偏树-可合并堆

Problem Monkey King

Solution

本题是裸的左偏树,一个模板就可以过了。对于每个操作对节点先删除/2再合并。
注意本题在HDU上评测特别坑,是多组数据,而且经常出现MLE的情况。很可能是其中初始化的问题。
斜堆可以更快。具体请查询IOI2015黄源河集训队论文

AC Code

#include "iostream"
#include "cstdio"
using namespace std;
struct LeftistTree{
    int dist,n,lc,rc,fa;
}a[100010];
int find(int x){
    while(a[x].fa!=x)x=a[x].fa;
    return x;
}
int n,m;
int x,y,ans,fx,fy,u,v,dx,dy;
int merge(int x,int y){
    if(x==0)return y;
    if(y==0)return x;
    if(a[x].n<a[y].n)swap(x,y);
    a[x].rc=merge(a[x].rc,y);
    a[a[x].rc].fa=x;
    if(a[a[x].lc].dist<a[a[x].rc].dist)swap(a[x].lc,a[x].rc);
    if(a[x].rc!=0)a[x].dist=a[a[x].rc].dist+1;
    else a[x].dist=0;
    return x;
}
int delt(int x){
    int ret=merge(a[x].lc,a[x].rc);
    a[a[x].lc].fa=ret;
    a[a[x].rc].fa=ret;
    a[x].lc=a[x].rc=a[x].dist=0;
    a[x].fa=x;
    return ret;
}
int main(){
    while(~scanf("%d",&n)){
        a[0].lc=0;a[0].rc=0;a[0].fa=0;
        for(int i=1;i<=n;i++)scanf("%d",&a[i].n),a[i].fa=i,a[i].dist=0,a[i].lc=0,a[i].rc=0;
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);    
            fx=find(x),fy=find(y);
            if(fx==fy)printf("-1\n");else{
                dx=delt(fx),dy=delt(fy);
                a[fx].n/=2;
                a[fy].n/=2;
                dx=merge(dx,fx);
                dy=merge(dy,fy);
                ans=merge(dx,dy);
                printf("%d\n",a[ans].n);
            }
        }
    }
}

 

posted @ 2017-01-18 19:48  skylynf  阅读(151)  评论(0编辑  收藏  举报