|Hdu 1512|可并堆|并查集|Monkey King

Hdu传送门
左偏树模板题,细节一定要注意

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ms(i,j) memset(i,j,sizeof i);
using namespace std;
const int MAXN = 100000 + 5;
struct node
{
    int l, r;//左偏树左、右孩子编号 
    int dis, key;//左偏树距离,键值 
    int f;//并查集father 
}lt[MAXN];
int n;
int m;
int find(int x) //并查集find 
{
    return (x==lt[x].f) ? (x) : (lt[x].f = find(lt[x].f)); 
}
void build(int rt, int v)//使rt初始化为v值 
{
    lt[rt].l = lt[rt].r = lt[rt].dis = 0;
    lt[rt].key = v; lt[rt].f = rt;
    if (rt==0) lt[rt].dis = -1;
}
int merge(int rtA, int rtB)//合并两棵树 
{
    if (rtA==0) return rtB;
    if (rtB==0) return rtA;
    if (lt[rtA].key<lt[rtB].key) swap(rtA, rtB);//大值左偏树要满足key(x)<key(parents[x]) 
    lt[rtA].r = merge(lt[rtA].r, rtB);//A的右子树和B合并 
    int &l = lt[rtA].l, &r = lt[rtA].r;//利用引用减少代码量,更加清晰
    lt[l].f = lt[r].f = rtA; //更新并查集 
    if (lt[l].dis<lt[r].dis) swap(l, r);//需要满足左偏性质dis(lc)>=dis(rc) 
    if (r==0) lt[rtA].dis = 0; else lt[rtA].dis = lt[r].dis+1;//算距离 
    return rtA;
}
int del(int rt)//删除rt节点 
{
    int l = lt[rt].l;
    int r = lt[rt].r;
    lt[l].f = l;
    lt[r].f = r;
    lt[rt].l = lt[rt].r = lt[rt].dis = 0;
    return merge(l, r);
}
int main()
{
    while (scanf("%d", &n)==1)
    {
        for (int i=1;i<=n;i++)
        {
            int x;
            scanf("%d", &x);
            build(i, x);
        }
        build(0, 0);
        scanf("%d", &m);
        for (int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d", &x, &y);
            int x1 = find(x);
            int x2 = find(y);//找最强壮的 
            if (x1==x2) {printf("-1\n");continue;}
            lt[x1].key>>=1;
            lt[x2].key>>=1;//之后插入的值 
            int left = del(x1), right = del(x2);
            left = merge(left, x1), right = merge(right, x2);
            left = merge(left, right);
            printf("%d\n", lt[left].key);
        }
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值