左偏树(Leftist Heap/Tree)简介及代码
左偏树是一种常用的优先队列(堆)结构。与二叉堆相比,左偏树可以高效的实现两个堆的合并操作。
左偏树实现方便,编程复杂度低,而且有着不俗的效率表现。
它的一个常见应用就是与并查集结合使用。利用并查集确定两个元素是否在同一集合,利用左偏树确定某个集合中优先级最高的元素。
#include <cstdio> #include <cstring> #include <algorithm> template <class T> struct HeapNode { typedef HeapNode<T> Node; Node* lch; Node* rch; T val; int dist; HeapNode(),rch(),val(_val),dist() {} void clear() { if(lch) lch->clear(); if(rch) rch->clear(); delete this; } }; template <class T,class Comp> struct LeftistHeap { typedef HeapNode<T> Node; typedef LeftistHeap<T,Comp> Heap; Node* root; Comp cmp; LeftistHeap():root() {} ~LeftistHeap() { clear(); } void clear() { if(root) root->clear(); root=; } Node* merge(Node* A,Node* B) { if(!A) return B; if(!B) return A; if(cmp(B->val,A->val)) std::swap(A,B); A->rch=merge(B,A->rch); if(!A->lch || A->rch->dist > A->lch->dist) std::swap(A->lch,A->rch); A->dist = (A->rch) ? A->rch->dist + : ; return A; } void push(const T& _val) { Node* nNode=new Node(_val); root=merge(root,nNode); } Heap& operator << (const T& _val) { push(_val); return *this; } T top() { return root->val; } void pop() { Node* temp=root; root=merge(temp->lch,temp->rch); delete temp; } Heap& operator >> (T& _dest) { _dest=top(); pop(); return *this; } void merge(Heap& _other) { this->root=merge(this->root,_other.root); _other.root=; } bool empty() { ; } };
Leftist Heap
定义左偏树节点的“距离”(dist)为从其右子树开始,一直向右走的路径总长。特别地,若某个节点没有右孩子,其dist值为0。
树中的每个节点都必须满足左孩子的dist值不小于右孩子(如果有的话)的dist值。
和大多数可并堆一样,左偏树的核心操作就是合并(Merge)操作。
(以下伪代码以小根堆为例,节点的数据域记为val)
function merge(Node* A,Node* B)
if(A和B中某一个为空) return 另一个 //特判,同时也是递归终止的条件
交换A和B(如果需要的话),使得A的val小于B的val
A->rch = merge(B,A->rch)
if(A的左孩子的dist小于右孩子的dist或A的左孩子不存在) 交换A的左、右孩子
根据A的右孩子更新A的dist
return A
实现细节详见代码。
有了合并操作,其他的也就水到渠成了:
插入(push):建立一个新节点,然后把它视为一个左偏树,将其与已有的合并。
删除(pop):删除其根节点,合并原先根节点的左右孩子。
附一道左偏树+并查集的练习题:
#include <cstdio> #include <cstring> #include <algorithm> template <class T> struct HeapNode { typedef HeapNode<T> Node; Node* lch; Node* rch; T val; int dist; HeapNode(),rch(),val(_val),dist() {} void clear() { if(lch) lch->clear(); if(rch) rch->clear(); delete this; } }; template <class T,class Comp> struct LeftistHeap { typedef HeapNode<T> Node; typedef LeftistHeap<T,Comp> Heap; Node* root; Comp cmp; LeftistHeap():root() {} ~LeftistHeap() { clear(); } void clear() { if(root) root->clear(); root=; } Node* merge(Node* A,Node* B) { if(!A) return B; if(!B) return A; if(cmp(B->val,A->val)) std::swap(A,B); A->rch=merge(B,A->rch); if(!A->lch || A->rch->dist > A->lch->dist) std::swap(A->lch,A->rch); A->dist = (A->rch) ? A->rch->dist + : ; return A; } void push(const T& _val) { Node* nNode=new Node(_val); root=merge(root,nNode); } Heap& operator << (const T& _val) { push(_val); return *this; } T top() { return root->val; } void pop() { Node* temp=root; root=merge(temp->lch,temp->rch); delete temp; } Heap& operator >> (T& _dest) { _dest=top(); pop(); return *this; } void merge(Heap& _other) { this->root=merge(this->root,_other.root); _other.root=; } bool empty() { ; } }; #include <functional> ; int N,M; int idx[maxN]; int father(int x) { return idx[x]==x ? x : idx[x]=father(idx[x]) ; } LeftistHeap<int,std::greater<int> > heap[maxN]; void init() { ;i<maxN;i++) heap[i].clear(); ;i<maxN;i++) idx[i]=i; } bool solve() { init(); if(scanf("%d",&N)==EOF) return false; ;i<=N;i++) { int s; scanf("%d",&s); heap[i].push(s); } scanf("%d\n",&M); while(M--) { int mk1,mk2; scanf("%d%d",&mk1,&mk2); int f1=father(mk1); int f2=father(mk2); if(f1==f2) { printf("-1\n"); continue; } int s1,s2; heap[f1]>>s1; heap[f2]>>s2; if(f1<f2) { idx[f2]=f1; heap[f1].merge(heap[f2]); ); )); heap[f1] << (s1>>) << (s2>>); } else { idx[f1]=f2; heap[f2].merge(heap[f1]); ); )); heap[f2] << (s1>>) << (s2>>); } } return true; } int main() { while(solve()); ; }
Problem:ZOJ P2334
左偏树(Leftist Heap/Tree)简介及代码的更多相关文章
- 『左偏树 Leftist Tree』
新增一道例题 左偏树 Leftist Tree 这是一个由堆(优先队列)推广而来的神奇数据结构,我们先来了解一下它. 简单的来说,左偏树可以实现一般堆的所有功能,如查询最值,删除堆顶元素,加入新元素等 ...
- 【BZOJ 1367】 1367: [Baltic2004]sequence (可并堆-左偏树)
1367: [Baltic2004]sequence Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Ou ...
- 左偏树 / 非旋转treap学习笔记
背景 非旋转treap真的好久没有用过了... 左偏树由于之前学的时候没有写学习笔记, 学得也并不牢固. 所以打算写这么一篇学习笔记, 讲讲左偏树和非旋转treap. 左偏树 定义 左偏树(Lefti ...
- 浅谈左偏树在OI中的应用
Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...
- [note]左偏树(可并堆)
左偏树(可并堆)https://www.luogu.org/problemnew/show/P3377 题目描述 一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 ...
- Monkey King(左偏树 可并堆)
我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...
- P3378 【模板】堆 (内含左偏树实现)
P3378 [模板]堆 题解 其实就是一个小根堆啦,STL就可以解决,但是拥有闲情雅致的我学习了Jelly_Goat的左偏树,增加了代码长度,妙啊 Solution 1 STL STL 里面prior ...
- 左偏树初步 bzoj2809 & bzoj4003
看着百度文库学习了一个. 总的来说,左偏树这个可并堆满足 堆的性质 和 左偏 性质. bzoj2809: [Apio2012]dispatching 把每个忍者先放到节点上,然后从下往上合并,假设到了 ...
- k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)
你谷数据够强了,以前的A*应该差不多死掉了. 所以,小伙伴们快来一起把YL顶上去把!戳这里! 俞鼎力的课件 需要掌握的内容: Dijkstra构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...
随机推荐
- JavaScript高级程序设计41.pdf
事件对象 在触发DOM上某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息. DOM中的事件对象 兼容DOM的浏览器会将event对象传入到事件处理程序中,无论指定事件处理 ...
- usaco 打扫食槽
Description 从前奶牛是不挑食的,但现在世道变了,她们变得非常挑剔.牧场里有N头奶牛,约翰 要向她们提供M种食物,第i头奶牛只会吃Pi号食物. 约翰每天都要打扫食槽,这件事非常累.奶牛沿着食 ...
- jQuery 的属性操作方法
jQuery 属性操作方法 下面列出的这些方法获得或设置元素的 DOM 属性. 这些方法对于 XML 文档和 HTML 文档均是适用的,除了:html(). 方法 描述 addClass() 向匹配的 ...
- 使用webdav实现文档共享
1.PC1上开启WebDAV的服务,添加创建规则:运行访问的路径.运行访问的用户(这里的用户是指PC1上的用户名和密码).访问权限
- Cookie案例分析
一.案例- 显示用户上次访问的时间 当用户第一次访问该页面的时候提示:你好,你是第一次访问本页面,当前时间为:2016-11-3 22:10:30 第n次访问该页面时:欢迎回来,你上次访问的时间是:2 ...
- 笔记本开了WIFI之后只能上QQ,上不了网页的解决方法
前几天拉了宽带之后,开了WIFI,发现WIFI能上网,但是电脑就上不了网页. 把本地连接的DNS指定一下,(电信)指定为202.102.192.68
- 再谈内存管理与ARC运行机制(一)
内存管理 内存在Objective-C开发中是一种相对稀缺的资源,拿Iphone4为例,它的内存只有512mb,所以妥善的处理好所创造,所使用的每个对象与变量都将成为一个问题.在ARC出现以前,同大部 ...
- [Usaco2006 Nov]Corn Fields牧场的安排 壮压DP
看到第一眼就发觉是壮压DP 然后就三进制枚举子集吧. 这题真是壮压入门好题... 对于dp[i][j] 表示第i行,j状态下前i行的分配方案数. 那么dp[i][j]肯定是从i-1行转过来的 那么由于 ...
- 假设但是学习java入门,请离开SSH稍远
我觉得有点累了步行上班,我想买一辆自行车.结果去了一看,想2500片.旁边的人说,2500所有最好加一些钱,买一挖电. 遂问电动车价格,3500,决定买.却被告知不如加点钱买小踏板摩托划算.于是看摩托 ...
- Linux内核源代码情景分析系列
http://blog.sina.com.cn/s/blog_6b94d5680101vfqv.html Linux内核源代码情景分析---第五章 文件系统 5.1 概述 构成一个操作系统最重要的就 ...