左偏树(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构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...
随机推荐
- zoj 3878 Convert QWERTY to Dvorak【好坑的模拟】
Convert QWERTY to Dvorak Time Limit: 2 Seconds Memory Limit: 65536 KB Edward, a poor copy typis ...
- 高级IO复用应用:聊天室程序
简单的聊天室程序:客户端从标准输入输入数据后发送给服务端,服务端将用户发送来的数据转发给其它用户.这里采用IO复用poll技术.客户端采用了splice零拷贝.服务端采用了空间换时间(分配超大的用户数 ...
- 375. Guess Number Higher or Lower II
最后更新 四刷? 极大极小算法..还是叫极小极大的.. 首先要看怎么能保证赢. 比如2个数,猜第一个猜第二个都能保证下一轮我们赢定了,为了少交钱,我们猜小的. 比如3个数,猜第二个才能保证下一轮再猜一 ...
- Java NIO使用及原理分析(二)
在第一篇中,我们介绍了NIO中的两个核心对象:缓冲区和通道,在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如 ...
- EasyUI-增删改操作
最近公司要用easyui,这里自己看了官网几篇文章,遇到些问题,大多数的问题都是敲代码的时候笔误,其他有些地方确实需要注意一下,这里做些笔记. 1.在mysql中建好表之后修改id字段为递增字段,发现 ...
- C# 保存和读取TreeView展开的状态
附件 http://files.cnblogs.com/xe2011/ReadAndSaveTreeViewState.rar 保存和读取TreeView展开的状态 节点{ImageIndex,Is ...
- Android开发:Handler Runnable和Thread之间的区别和联系 应用--------------------看完本篇,从此一览无余!
http://blog.csdn.net/yanzi1225627/article/details/8582081 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnab ...
- 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护
本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context ↳an ...
- uva 167 - The Sultan's Successors(典型的八皇后问题)
这道题是典型的八皇后问题,刘汝佳书上有具体的解说. 代码的实现例如以下: #include <stdio.h> #include <string.h> #include < ...
- Java获取当前目录方法整理
假设项目路径是E:\Workspaces\MyProgram\FilePath 1.使用System.getProperty("user.dir"),获得项目的根路径,返回Stri ...