经过一天的学习,总会感觉十分的充实并且会感觉状态非常好,然而今天的考试却让我突然醒悟,认识到自己其实并没有精通。拿到题目,就先浏览了全篇,发现好像自己并不会做任何一道题,就开始放水十分无奈地想题了。想了一会以后,突然发现第一题就是一个线段树,只需要再加一个左区间的右部分和右区间的左部分就行了,这是一道大水水水水水水水水水水水水题呀!于是就满怀激动的开始敲代码。然而在打了一会儿之后,猛地意识到这要加一个lazy标记!这使我十分的震惊,就很无奈的望着自己的代码,又开始加有关lazy的部分。可是就这样2个半小时之后,仍然没调出来,便只好打了个暴力解法交了上去,但最终这个解法也爆零了,让我很桑心,本来思路都已经和标程一模一样了,却由于没有练习足够的版,题而爆零,这已经是一个不容忽视的问题了。
在无奈的打完第一题暴力后,就十分慌乱地开始看后两道题。由于我之前看第二题时,脑子仍然在想第一题,就吧、把第二题想复杂了,一看时间又不够了,就直接跳过看第三题去了。导致我的50分低保也丢了。然而面对今天最难的第三题(。。。)我更加的束手无策,打了个暴力却WA掉了。
这真是悲伤的一天,于是在化悲伤为力量并吃了饱饱的一餐后,我开始学习左偏树,大呼“苟利国家生死以,竹外桃花三两枝,这数据结构竟然如此有用!”,便把它收纳到我的博客里面,好好学习。
左偏树
baidu: 左偏树(Leftist Tree)是一种可并堆的实现。左偏树是一棵二叉树,它的节点除了和二叉树的节点一样具有左右子树指针( left, right)外,还有两个属性,键值和距离(dist)。
(什么乱七八糟的)
左偏树的4条性质:
(1)节点的键值小于或等于它的左右子节点的键值
(2)节点的左子节点的距离不小于右子节点的距离
(3)节点的距离等于它的右子节点的距离加1
(4)一颗N个节点的左偏树距离最多为log(N+1)-1
其实在画过一颗左偏树并模拟之后,这四条性质也就十分简单易懂了。同时,这四条性质还可以扩展出一些其他的东西,例如:
1. 若左偏树的距离为一定值,则节点数最少的左偏树是完全二叉树。
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 10000;
struct Tree{
int value;
int dist;
Tree *left,*right;
};
Tree* tree[MAXN];
int distance(Tree* t){
return t==NULL?0:t->dist;
}
void fixdist(Tree* t){
if(distance(t->left) < distance(t->right)){
swap(t->left,t->right);
}
t->dist = distance(t->right)+1;
}
Tree* merge(Tree* a,Tree* b){//合并
if(a==NULL)return b;
if(b==NULL)return a;
if(b->value > a->value){//最大堆
swap(a,b);
}
a->right = merge(a->right,b);
fixdist(a);
return a;
}
Tree* delMax(Tree* t){
if(t!=NULL){
return merge(t->left,t->right);
}
return NULL;
}
void init(Tree* &t,int value){
t = new Tree;
t->dist = 1;
t->value = value;
t->left = t->right = NULL;
}
Tree* insert(Tree* t,int value){//插入(可以视为合并)
Tree* p;
init(p,value);
return merge(t,p);
}
int main()
{
}