hdu 1512 Monkey King and ZOJ 2334

来源:互联网 发布:供应链网络鲁棒性 编辑:程序博客网 时间:2024/04/30 10:14

Monkey King

很裸的左偏树题目。直接应用就可以了。

/*author        : 中南大学 陈安PROG          : hdu 1512data structure: 左偏树操作:采用最大左偏树,所以每群猴子中权值最大的一定在树根1.查询每群猴子中权值最大的,采用并查集,否则容易爆栈2.对于修改操作,可以分解为如下步骤:a.删除树根,合并左右子树,b.修改原树根的值,c.合并树根与新的子树*/#include <cstdio>#include <cstring>#define maxn 100010struct Tree{    int l ;    int r ;    int v ;    int d ;}tree[maxn];int p[maxn];int n ;inline void InitTree(Tree &a){    a.l = -1 ;    a.r = -1 ;    a.v = -1 ;    a.d = 0  ;}inline void read(){    int x ;    for(int i = 1 ; i <= n ; i ++){        InitTree(tree[i]) ;        scanf("%d" , &tree[i].v) ;    }}inline int Get_Max(int x){    return tree[x].v ;}inline void swap(int &x ,int &y){    int t = x ;    x = y ;    y = t ;}int Merge(int x , int y){    if(x == -1) return y ;    if(y == -1) return x ;    if(tree[y].v > tree[x].v)        swap(x , y) ;    tree[x].r = Merge(tree[x].r , y) ;    if(tree[x].r != -1){        if(tree[x].l == -1 || tree[ tree[x].r ].d > tree[ tree[x].l ].d){            swap(tree[x].l , tree[x].r) ;        }    }    if(tree[x].r == -1){        tree[x].d = 0 ;    }    else{        tree[x].d = tree[tree[x].r].d + 1 ;    }    if(tree[x].l != -1){        p[ tree[x].l ] = x ;    }    if(tree[x].r != -1){        p[tree[x].r] = x ;    }    p[x] = x ;    return x ;}int Del_Max(int x){    int root = x ;    int val = tree[x].v ;    root = Merge(tree[root].l , tree[root].r) ;    //初始化该节点的值    InitTree(tree[x]) ;    tree[x].v = val   ;    return root ;}int Insert(int x , int y){    return Merge(x , y) ;}int find(int x){    if(p[x]==x)        return x ;    else        return (p[x] = find(p[x])) ;}void joint(int x , int y){    int rx = find(x) ;    int ry = find(y) ;    if(rx != ry)        p[rx] = ry ;}void solve(){    int op ;    int x  ;    int y  ;    int rx ;    int ry ;    scanf("%d" ,&op) ;    for(int i = 0 ; i < op ; i ++){        scanf("%d%d" , &x , &y) ;        rx = find(x) ;        ry = find(y) ;        if(rx == ry)            printf("-1\n") ;        else{            //首先将根节点删除,            int rr1 = Del_Max(rx) ;            int rr2 = Del_Max(ry) ;            //将根节点的值减半            tree[rx].v = tree[rx].v >>1 ;            tree[ry].v = tree[ry].v >>1 ;            //然后将之前删掉的节点重新插入到树中            rr1 = Insert(rr1 , rx) ;            rr1 = Insert(rr1 , ry) ;            //将两棵左偏树合并            rr1 = Merge(rr1 , rr2) ;            printf("%d\n" , Get_Max(rr1)) ;        }    }}void init(){    for(int i = 1 ; i <= n ; i ++){        p[i] = i ;    }}int main(){    while(scanf("%d" , &n) != EOF){        init()  ;        read()  ;        solve() ;    }    return 0 ;}