[HDU1512] Monkey King

题意

N只好斗的猴子.开始,他们各自为政,互不相干.但是猴子们不能消除争吵,但这仅仅发生在两只互不认识的猴子之间.当争吵发生时,争吵的两只猴子都会求助他们各自最强壮的朋友,并且决斗.当然,决斗之后,两只猴子及他们所有的朋友都相互认识了,并且成为朋友,争吵将不会在他们之间发生.
假定每一只猴子有一个强壮值,在每次决斗之后变为原来的一半(例如,10将为变为5,5将会变为2).
假定每一只猴子认识他自己. 也就是当他发生争吵,并且自己是他的朋友中最强壮的,他将代表自己进行决斗.
对于每一次争吵,如果两只猴子认识,输出-1,否则输出一个数,表示决斗后朋友中最强壮猴子的强壮值.

题解

每次两个猴子争吵相当于两个点集的合并,每个点集都需要维护最大值,又要维护点之间的连通性。故用左偏树维护最大值与合并,并查集维护连通性。

代码

/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v)  for(i=v.begin();i!=v.end();i++)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}

#define  kN  100010LL

struct lt {
    lt *l, *r;
    int w, d;
    lt();
    lt(int w);
}*null=new lt();
lt::lt() { l=r=null;w=d=0; }
lt::lt(int w): w(w) { l=r=null;d=0; }
lt* Init(int x) { return new lt(x); }
lt* Merge(lt*u,lt*v) {
    if (u == null) return v;
    if (v == null) return u;
    if (u->w < v->w) std::swap(u,v);
    u->r = Merge(u->r,v);
    if (u->l->d < u->r->d) std::swap(u->l,u->r);
    u->d = u->r->d+1;
    return u;
}
void Insert(lt*&u,int x) { u = Merge(u,Init(x)); }
int Top(lt*u) { return u->w; }
void Pop(lt*&u) { lt*tmp = u; u = Merge(u->l,u->r); delete tmp; }
bool Empty(lt*u) { return u == null; }

int n, fa[kN] = {0};
lt*q[kN];

inline int GetAnc(int u) { return fa[u]?fa[u]=GetAnc(fa[u]):u; }

#define r(x)   read(x)
inline void work() {
    int i, u, v, wu, wv;
    Rep (i,1,n)
        r(v), q[i] = Init(v), fa[i] = 0;
    r(i);
    while (i --> 0) {
        r(u), r(v);
        u = GetAnc(u), v = GetAnc(v);
        if (u == v) { puts("-1"); continue; }
        wu = Top(q[u]), Pop(q[u]), wu >>= 1, Insert(q[u],wu);
        wv = Top(q[v]), Pop(q[v]), wv >>= 1, Insert(q[v],wv);
        printf("%d\n", std::max(Top(q[u]),Top(q[v])));
        fa[v] = u;
        q[u] = Merge(q[u],q[v]);
    }
}

int main() {
    while (scanf("%d",&n)!=EOF)work();
    END: getchar(), getchar();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值