• 左偏树


    左偏堆可以完成优先队列的插入节点,出队,还有合并。

    合并:

    int merge(int a,int b){
        if(a==0)return b;
        if(b==0)return a;
        if(heap[a].v<heap[b].v)swap(a,b);
        heap[a].r=merge(heap[a].r,b);
        heap[heap[a].r].f=a;
        if(heap[heap[a].l].dis<heap[heap[a].r].dis)swap(heap[a].l,heap[a].r);
        if(heap[a].r==0)heap[a].dis=0;
        else heap[a].dis=heap[heap[a].r].dis+1;
        return a;
    }

    出队:

    int pop(int a){
        int l=heap[a].l;
        int r=heap[a].r;
        heap[l].f=l;
        heap[r].f=r;
        heap[a].l=heap[a].r=heap[a].dis=0;
        return merge(l,r);
    }

    例题:ZOJ2334

    题目大意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。

    #include<cstdio>
    #include<iostream>
    #define N 100010
    using namespace std;
    int n,m;
    struct node{
        int v,dis,l,r,f;
    };node heap[N];
    int find(int x){
        if(x==heap[x].f)return x;
        return heap[x].f=find(heap[x].f);
    }
    int merge(int a,int b){
        if(a==0)return b;
        if(b==0)return a;
        if(heap[a].v<heap[b].v)swap(a,b);
        heap[a].r=merge(heap[a].r,b);
        heap[heap[a].r].f=a;
        if(heap[heap[a].l].dis<heap[heap[a].r].dis)swap(heap[a].l,heap[a].r);
        if(heap[a].r==0)heap[a].dis=0;
        else heap[a].dis=heap[heap[a].r].dis+1;
        return a;
    }
    int pop(int a){
        int l=heap[a].l;
        int r=heap[a].r;
        heap[l].f=l;
        heap[r].f=r;
        heap[a].l=heap[a].r=heap[a].dis=0;
        return merge(l,r);
    }
    void work(){
        for(int i=1;i<=n;i++){
            scanf("%d",&heap[i].v);
            heap[i].dis=heap[i].l=heap[i].r=0;
            heap[i].f=i;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int a,b;scanf("%d%d",&a,&b);
            int aa=find(a),bb=find(b);
            if(aa==bb){
                printf("-1
    ");continue;
            }
            heap[aa].v/=2;
            int u1=pop(aa);
            u1=merge(u1,aa);
            heap[bb].v/=2;
            int u2=pop(bb);
            u2=merge(u2,bb);
            printf("%d
    ",heap[merge(u1,u2)].v);
        }
    }
    int main(){
        while(scanf("%d",&n)!=EOF){
            work();
        }
        return 0;
    }

     论文链接:http://wenku.baidu.com/link?url=t55yGX-UkUdEXBhpvBwuzjKP16F7lFl0RKSVVBBW5zXWRB7rRXvLLj1jM-pzhbH834hQl0KKT4va247VmSepsGDSrYF1E3le_WpnKc2xfCi

  • 相关阅读:
    【Linux】防火墙命令
    【MySQL】mysql分组后重命名
    【SpringBoot】全局配置Long转String,解决前端接收时精度丢失的问题
    【VSCode】vscode运行命令时提示“因为在此系统上禁止运行脚本”
    【Mybatis】mybatisplus代码生成器【逆向工程】搭配Lombok和swagger2
    【Linux】赋予root权限
    【MySQL】mysql模糊匹配多个字段
    idea为新创建的类增加个人注释模板
    【Linux】学习笔记:(一)常用命令大全
    Navicat查看数据库的密码
  • 原文地址:https://www.cnblogs.com/harden/p/6155279.html
Copyright © 2020-2023  润新知