美文网首页
LUOGU 3377 左偏树

LUOGU 3377 左偏树

作者: 苏子旃 | 来源:发表于2019-02-18 22:08 被阅读0次
Description

如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
操作1 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
操作2 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)

Input Format

第一行包含两个正整数N,M,分别表示一开始小根堆的个数和接下来操作的个数。
第二行包含N个正整数,其中第i个正整数表示第i个小根堆初始时包含且仅包含的数。
接下来M行每行2个或3个正整数,表示一条操作,格式如下:
操作1 1 x y
操作2 2 x

Output Format

输出包含若干行整数,分别依次对应每一个操作2所得的结果。

Sample Input

5 5
1 5 4 2 3
1 1 5
1 2 5
2 2
1 4 2
2 2

Sample Output

1
2

Constraints

对于100%的数据:N \leq 100000,M \leq 100000

CCYOS

这是一道左偏树板子题。感谢徐灏诚juju的讲课,挺好理解的。

  1. 左偏树
    可并堆的一种,有如下性质:
    a.堆性质
    保证每颗子树的根节点的权值小于它的左儿子和右儿子的权值,这样可以O(1)删除本堆中的最小节点。
    b.左偏性质
    定义有一颗子树为空的节点为外节点
    定义每个点的dist为这个点到它的后代中的外节点的最短距离
    左偏树满足dist[rs] \leq dist[ls]但是这并不代表左偏树左子树比右子树深度大
    所以有dist[x] = dist[ls] + 1不可能会出现单右子树的情况,所以令dist[0] = -1来使下图的根(外节点)的dist正确。 权值为5的节点的dist为0

2)左偏树的合并
设有两棵左偏树A,B需要合并。
左偏树的合并是努力让B和A的右子树合并,简称把我的兄弟(?)变成我的儿子,同时要维护左偏树的性质。
a.有一棵树为空:直接返回该子树。

if(!x||!y)return x + y;

b.没有空子树:
为了维护堆性质,选取A,B中根节点权值较小的左偏树作为A树。
向下合并,将A的右儿子和B合并的树的根节点作为A的右儿子。
为了维护左偏性质,若左儿子的dist值小于右儿子的dist值,交换左右儿子。
更新A树根节点的dist,rt及左右儿子的rt
返回合并完毕的左偏树A

inline int Merge(int x,int y){
    if(!x || !y)return x + y;
    if(tr[x].val > tr[y].val)swap(x,y);
    if(tr[x].val == tr[y].val && x > y)swap(x,y);
    rs = Merge(rs,y);
    if(tr[ls].dis < tr[rs].dis)swap(ls,rs);
    tr[ls].rt = tr[rs].rt = tr[x].rt = x;
    tr[x].dis = tr[rs].dis + 1;
    return x;
}
  1. 左偏树的删除
    仅限于删除最小节点。
    O(1)删除最小节点,重置左右儿子的根,合并左右儿子。
inline void Pop(int x){
    tr[x].val = -1;
    tr[ls].rt = ls;tr[rs].rt = rs;
    tr[x].rt = Merge(ls,rs);
}

注意
a) Merge(rs,y)要更新给rs。
b) 注意题目要求的输出。
c) tr[0].dist = -1。
code

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;

int N,M;

struct tree{
    int Ls,Rs,rt,val,dis;
}tr[100005];

inline int read(){
    int ret = 0,fl = 1;
    char c = getchar();
    for(;!isdigit(c)&&c != '-';c = getchar())if(c == '-')fl = 0;
    for(;isdigit(c);c = getchar())ret = (ret << 3) + (ret << 1) + c - 48;
    return fl ? ret : -ret;
}

#define ls tr[x].Ls
#define rs tr[x].Rs
inline int findf(int x){return tr[x].rt == x ? x : tr[x].rt = findf(tr[x].rt);}

inline int Merge(int x,int y){
    if(!x || !y)return x + y;
    if(tr[x].val > tr[y].val)swap(x,y);
    if(tr[x].val == tr[y].val && x > y)swap(x,y);
    rs = Merge(rs,y);
    if(tr[ls].dis < tr[rs].dis)swap(ls,rs);
    tr[ls].rt = tr[rs].rt = tr[x].rt = x;
    tr[x].dis = tr[rs].dis + 1;
    return x;
}

inline void Pop(int x){
    tr[x].val = -1;
    tr[ls].rt = ls;tr[rs].rt = rs;
    tr[x].rt = Merge(ls,rs);
}

int main(){
//  freopen("testdata.in","r",stdin);
//  freopen("testdata.out","w",stdout);

    N = read();M = read();tr[0].dis = -1;
    for(register int i = 1;i <= N;++i)
        tr[i].val = read(),tr[i].rt = i;
    for(register int i = 1;i <= M;++i){
        int op = read();
        if(op == 1){
            int x = read();int y = read();
            if(tr[x].val == -1||tr[y].val == -1)continue;
            x = findf(x);y = findf(y);
            if(x == y)continue;
            tr[x].rt = tr[y].rt = Merge(x,y);
        }
        else{
            int x = read();
            if(tr[x].val == -1)printf("-1\n");
            else{
                x = findf(x);
                printf("%d\n",tr[x].val);Pop(x);
            }
        }
    }
    return 0;
}

相关文章

  • LUOGU 3377 左偏树

    Description 如题,一开始有个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:操作1 将...

  • 左偏树

    bzoj1455 罗马游戏Description罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独...

  • 数据结构: 可合并堆-左偏树 Leftist Tree

    数据结构: 可合并堆-左偏树 来自维基百科左偏树(英语: leftist tree或leftist heap), ...

  • 左偏树和斜堆

    左偏树的性质 本节点的键值key小于其左右子节点键值key(与二叉堆相同); 本节点的左子节点的距离大于等于本节点...

  • 深圳猫友交流

    W:angelo3377

  • 线段树 Segtree

    原题 https://www.luogu.org/problemnew/show/P3373 (手写线段树 wKw...

  • 数据结构:左偏堆

    左偏堆简介 又称左偏树、左倾堆,这么多名字都带个左,那就是因为它向左倾斜,和二叉堆一样都是一种优先队列实现方式。 ...

  • LUOGU 3384 树链剖分

    LUOGU 3384Description如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需...

  • 2020-09-23 表达式括号匹配

    https://www.luogu.com.cn/problem/P1739[https://www.luogu....

  • c++第七天作业

    1、luogu1423并完成试炼场循环循环循环! 2、luogu陶陶摘苹果。

网友评论

      本文标题:LUOGU 3377 左偏树

      本文链接:https://www.haomeiwen.com/subject/kihgeqtx.html