因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教。

左偏树:

什 么是(fzy说)左偏树啊?

前置知识:

  左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点的为0。

  堆:左偏树是个堆。

  关于左偏性质:可以帮助堆合并(研究深了我也不懂的,看代码理解)

  对于任意的节点,dist[leftson]>=dist[rightson],体现了左偏性质。

  同理可得:对于任意右儿子的父亲节点的dist自然等于右儿子的dist+1喽

关于各种操作:

merge:

  是插入操作的函数,具体步骤如下:

  1.对于两个堆x,y,判断x,y是否为0,如果有一个为0,相当于没合并,直接返回另一个有元素的堆。

  2.找到value值更大的那个堆头放到顶上,如果value值一样的话就按堆顶编号来排序。为了方便代码实现,我们可以规定x为符合条件(小,大跟堆)的那个堆头,然后如果y符合条件就交换x,y值。

  3.既然堆头找着了,就可以进一步的合并堆头右儿子和y堆了(为了尽量保证左偏的性质)。如此递归下去,随着新堆头被一次次确定,最终这个堆会被一点一点融合到另一个堆中。

  4.但是,鉴于合成完后,不一定能够保证左子树的dist值一定会比右字数的大,我们只要判断一下是否符合左偏性质,如果不符合,就交换一下当前节点左右子树就行了。因为是递归执行,从更深节点一层一层上来,那么必然的整个堆会符合左偏性质。然后更新一下dist为右子树dist+1.一次merge完成。

代码:

  1. inline int merge(int x, int y)
  2. {
  3. if(!x||!y)return x+y;
  4. if(tree[x].value>tree[y].value||(tree[x].value==tree[y].value&&x>y))swap(x,y);
  5. rs=merge(rs,y);
  6. if(tree[ls].dist<tree[rs].dist)swap(ls, rs);tree[ls].rt=tree[rs].rt=tree[x].rt=x,tree[x].dist=tree[rs].dist+;
  7. //更新dist
  8. return x ;
  9. }

2.pop弹出函数:

弹出函数,即弹出堆顶。方法很简单:没有了堆顶,整个左偏树就被分为了两个小的左偏树。我们只要忽略掉堆顶合并(merge)两个小的左偏树即可。

注意事项:不要忘了堆顶元素相关信息还原为初始。

代码:

  1. inline void pop(int x)//弹出x为堆顶的堆
  2. {
  3. tree[x].value=-,tree[ls].rt=ls,tree[rs].rt=rs;
  4. tree[x].rt=merge(ls,rs);
  5. }

3.get函数:

没啥可说的,就是并查集找父亲并且路径压缩。

代码:

  1. int get(int x)
  2. {
  3. return x==tree[x].rt?x:tree[x].rt=get(tree[x].rt);
  4. }

三个函数代码已经完结。

main函数内根据题意进行模拟即可。

总代码:

  1. #include<queue>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #define N 100003
  7. #define ls tree[x].son[0]
  8. #define rs tree[x].son[1]
  9. using namespace std;
  10. int read()
  11. {
  12. int ans=;
  13. char ch=getchar(),last=' ';
  14. while(ch<''||ch>'')last=ch,ch=getchar();
  15. while(ch>=''&&ch<='')ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
  16. return last=='-'?-ans:ans;
  17. }
  18. inline void swap(int &x,int &y)
  19. {
  20. x^=y^=x^=y;
  21. }
  22. int n,num,hea[N],t,judge,b,c;
  23. struct tre{
  24. int son[],rt,dist,value;
  25. }tree[N];
  26. inline int merge(int x, int y)
  27. {
  28. if(!x||!y)return x+y;
  29. if(tree[x].value>tree[y].value||(tree[x].value==tree[y].value&&x>y))swap(x,y);
  30. rs=merge(rs,y);
  31. if(tree[ls].dist<tree[rs].dist)swap(ls, rs);tree[ls].rt=tree[rs].rt=tree[x].rt=x,tree[x].dist=tree[rs].dist+;
  32. //更新dist
  33. return x ;
  34. }
  35. int get(int x)
  36. {
  37. return x==tree[x].rt?x:tree[x].rt=get(tree[x].rt);
  38. }
  39. inline void pop(int x)//弹出x为堆顶的堆
  40. {
  41. tree[x].value=-,tree[ls].rt=ls,tree[rs].rt=rs;
  42. tree[x].rt=merge(ls,rs);
  43. }
  44. int main(){
  45. n=read(),t=read();tree[].dist=-;
  46. for (int i=;i<=n;i++)
  47. tree[i].rt=i,scanf("%d",&tree[i].value);//并差集初始化+输入
  48. for (int i=;i<=t;i++){
  49. judge=read(),b=read();
  50. if (judge==){
  51. c=read();
  52. if (tree[b].value==-||tree[c].value==-) continue ;
  53. int f1=get(b),f2=get(c);if(f1!=f2)tree[f1].rt=tree[f2].rt=merge(f1,f2);//合并操作
  54. }
  55. else {
  56. if(tree[b].value==-)printf("-1\n") ;
  57. else printf("%d\n",tree[get(b)].value),pop(get(b)) ;//输出并弹出
  58. }
  59. }
  60. return ;
  61. }

完结。

彩蛋:有趣的东西:

极度真实的左偏树。

来自dalao

P3377 【模板】左偏树(可并堆) 左偏树浅谈的更多相关文章

  1. 【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)

    2333: [SCOI2011]棘手的操作 Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边 ...

  2. 浅谈Java中的栈和堆

    人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...

  3. [note]左偏树(可并堆)

    左偏树(可并堆)https://www.luogu.org/problemnew/show/P3377 题目描述 一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 ...

  4. Monkey King(左偏树 可并堆)

    我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...

  5. bzoj2809 [Apio2012]dispatching——左偏树(可并堆)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809 思路有点暴力和贪心,就是 dfs 枚举每个点作为管理者: 当然它的子树中派遣出去的忍者 ...

  6. 浅谈左偏树在OI中的应用

    Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...

  7. 笔试算法题(46):简介 - 二叉堆 & 二项树 & 二项堆 & 斐波那契堆

    二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者 ...

  8. 洛谷——P3919 【模板】可持久化数组(可持久化线段树/平衡树)

    P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...

  9. 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树...

    上篇文章我们主要介绍了线性数据结构,本篇233酱带大家康康 无所不在的非线性数据结构之一:树形结构的特点和应用. 树形结构,是指:数据元素之间的关系像一颗树的数据结构.我们看图说话: 它具有以下特点: ...

随机推荐

  1. OpenCV.资料(20190717)

    1.opencv将图片转换为视频 - zeng_haoyu的博客 - CSDN博客.html(https://blog.csdn.net/hy13684802853/article/details/8 ...

  2. matplotlib画图总结--多子图布局

    1.subplot布局 subplot(nrows, ncols, index, **kwargs) subplot(pos, **kwargs) subplot(ax) x=[1,2,3] valu ...

  3. find the mincost route【无向图最小环】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1599 Problem Description 杭州有N个景区,景区之间有一些双向的路来连接,现在860 ...

  4. Collection集合常用的功能

    package demo06; import java.util.ArrayList;import java.util.Collection; /** java.util接口 Collection&l ...

  5. RxJava基本使用

    更多文章请点击链接:http://77blogs.com/?p=162 转载请标明出处:https://www.cnblogs.com/tangZH/p/12088300.html,http://77 ...

  6. superset部署

    superset功能概述: 丰富的数据可视化集 易于使用的界面,用于探索和可视化数据 创建和共享仪表板 与主要身份验证提供程序集成的企业级身份验证(通过Flask AppBuilder进行数据库,Op ...

  7. 最长回文 HDU - 3068(马拉车算法)

    Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入 ...

  8. 剑指offer46:圆圈中最后剩下的数字(链表,递归)

    1 题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随 ...

  9. 基于DNS(Consul)高可用

    DNS 推荐从Bind-DLZ入手,资料多可控制度更好(查询DNS记录SQL可定制)据说性能差 Bind-DLZhttps://www.cnblogs.com/saneri/p/8178065.htm ...

  10. linux实现一个定时任务

    设置定时任务删除logs脚本数据 编写脚本   touch cleanLogs.sh #! /bin/sh -name "*.log*" -exec rm -f {} \; 使用r ...