ZOJ 2334 Monkey King 可并堆左偏树

----------

int n,m;

class LeftistTree{
private:
    int tot,v[maxn],l[maxn],r[maxn],d[maxn];
public:
    int merge(int x,int y){
        if (!x) return y;
        if (!y) return x;
        if (v[x]<v[y]) swap(x,y);
        r[x]=merge(r[x],y);
        if (d[l[x]]<d[r[x]]) swap(l[x],r[x]);
        d[x]=d[r[x]]+1;
        return x;
    }
    int newNode(int x){
        tot++;
        v[tot]=x;
        l[tot]=r[tot]=d[tot]=0;
        return tot;
    }
    int insert(int rt,int val){
        return merge(rt,newNode(val));
    }
    int top(int rt){
        return v[rt];
    }
    int pop(int rt){
        return merge(l[rt],r[rt]);
    }
    void clear(){
        tot=0;
    }
}tr;
int lp[maxn];
int pa[maxn];
void makeset(int n){
    for (int i=0;i<=n;i++) pa[i]=i;
}
int findset(int x){
    if (x!=pa[x]) pa[x]=findset(pa[x]);
    return pa[x];
}
void unionset(int x,int y){
    x=findset(x);
    y=findset(y);
    if (x!=y){
        pa[x]=y;
        lp[y]=tr.merge(lp[x],lp[y]);
    }
}

int main(){
    while (~scanf("%d",&n)){
        makeset(n);
        tr.clear();
        for (int i=1;i<=n;i++){
            int v;
            scanf("%d",&v);
            lp[i]=tr.newNode(v);
        }
        scanf("%d",&m);
        for (int i=1;i<=m;i++){
            int l,r;
            scanf("%d%d",&l,&r);
            if (findset(l)==findset(r)) printf("-1\n");
            else{
                int newPower,newRoot;
                newPower=tr.top(lp[findset(l)])/2;
                newRoot=tr.pop(lp[findset(l)]);
                lp[findset(l)]=tr.insert(newRoot,newPower);
                newPower=tr.top(lp[findset(r)])/2;
                newRoot=tr.pop(lp[findset(r)]);
                lp[findset(r)]=tr.insert(newRoot,newPower);
                unionset(l,r);
                printf("%d\n",tr.top(lp[findset(l)]));
            }
        }
    }
	return 0;
}


----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值