COGS 526 又是一道模板题——左偏树

这不刚刚学会写左偏树嘛,COGS上正好有个左偏树的分类,本来想做第一道,USACO Jan09的安全路径,可是那道题谜一样的题目描述吓到我了,于是就看了下面那一道,就是这道题。相当于又粘了一下模板。
只需要在结构体中加上一个fa,方便给出节点找出树根,再用并查集判断两只猴子是否在一个堆中(就是已经是朋友的都在一个大根堆中,最开始有n个大根堆)就可以。我没仔细想是否可以直接用并查集的树根表示堆的树根,或者只需要用并查集来做(偷个懒嘿嘿)。
每次给出要争吵的猴子a和b,用并查集判断如果他们是朋友输出-1,如果不是,找出a,b在的堆的根A,B,分别合并A,B的左右孩子,再合并一下。之后把A,B的数据更改一下:权值除以2,左右孩子设为0,再插入到堆中即可。最后输出堆顶。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

int n, m, f[100005];

struct node{
    int w, lc, rc, h, fa;
}t[100005];

int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}

int merge(int A, int B){
    if(!A) return B;
    if(!B) return A;
    if(t[A].w < t[B].w) swap(A, B);
    t[A].rc = merge(t[A].rc, B);           
    if(t[t[A].lc].h < t[t[A].rc].h) swap(t[A].lc, t[A].rc);
    if(t[A].rc) t[A].h = t[A].rc+1;
    else t[A].h = 0;
    if(t[A].lc) t[t[A].lc].fa = A;
    if(t[A].rc) t[t[A].rc].fa = A;
    t[A].fa = 0;
    return A;
} 

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &t[i].w);   
        f[i] = i;
    }
    scanf("%d", &m);
    while(m--){
        int a, b;
        scanf("%d %d", &a, &b);
        int fa = find(a), fb = find(b);
        if(fa == fb) printf("-1\n");
        else{
            int A = fa, B = fb, ra, rb, r1, r2, r3;
            while(t[A].fa) A = t[A].fa;
            while(t[B].fa) B = t[B].fa;
            t[A].w /= 2;   t[B].w /= 2;
            ra = merge(t[A].lc, t[A].rc);
            rb = merge(t[B].lc, t[B].rc);
            t[A].lc = t[A].rc = t[B].lc = t[B].rc = 0;
            r1 = merge(ra, rb); 
            r2 = merge(r1, A);
            r3 = merge(r2, B);
            f[fa] = fb;
            printf("%d\n", t[r3].w);
        }
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值