【OI赛第五场】T1树

来源:互联网 发布:初级会计职称试题软件 编辑:程序博客网 时间:2024/05/12 07:15
题意
一颗二叉树,知道中序遍历是1~n,告诉你层次遍历,求字典序最小的先序遍历。
样例输入
5
4 2 5 1 3
样例输出
4 2 1 3 5
数据范围:n<=3*10^5

题解
题目的关键是把这颗树建出来,怎么建呢?就是找根,根就是一段区间在层次遍历中出现最早的,然后递归左右子树,现在的关键是求一段区间的最早出现的值。用一个B数组记录1~n中每个数出现的时间,用ST表,或线段树就可以A掉这题。复杂度O(nlogn);但这不是本题的重点。重点是用笛卡尔树O(n)的求。下面介绍一下笛卡尔树。

笛卡尔树

笛卡尔树又称笛卡儿树,在数据结构中属于二叉树的一种。

笛卡尔树结构由Vuillmin在解决范围搜索的几何数据结构问题时提出的,从数列中构造一棵笛卡尔树可以线性时间完成,需要采用基于栈的算法来找到在该数列中的所有最近小数。由此可知,笛卡尔树是一种特定的二叉树数据结构,可由数列构造,在范围最值查询、范围top k查询(range top k queries)等问题上有广泛应用。它具有堆的有序性,中序遍历可以输出原数列。

笛卡尔树是一棵二叉树,树的每个节点有两个值,一个为key,一个为value。光看key的话,笛卡尔树是一棵二叉搜索树,每个节点的左子树的key都比它小,右子树都比它大;光看value的话,笛卡尔树有点类似堆,根节点的value是最小(或者最大)的,每个节点的value都比它的子树要大。

构造笛卡尔树的过程:

使用数据结构栈,栈中保存的始终是右链,即根结点、根结点的右儿子、根结点的右儿子的右儿子……组成的链
并且栈中从栈顶到栈底key依次减小


如果按照从后到前的顺序判断一个元素是否大于A[i],则每次插入的时间复杂度为O(k+1)
k为本次插入中移除的右链元素个数。因为每个元素最多进出右链各一次,所以整个过程的时间复杂度为O(N)。

从前往后遍历A[i],
1.对于每一个A[i],从栈中找出(从栈顶往栈底遍历,或者从数组后往前遍历)第一个小于等于A[i]的元素
2.如果找到,i.parent为sta[k],同时sta[k].r=i,即i为sta[k]的右子树,
3.如果栈中存在比A[i]大的元素 这些元素肯定是出栈了,这个问题最后的代码统一表示。
同时,sta[k+1].parent=i; i.l=sta[k+1] 即sta[K+1]为i的左子树
4.最后i入栈,比i大的A[i]都自动出栈了。


例子如下。
0 1 2 3 4 5 6 7 8  9      .....key
3 2 4 5 6 8 1 9 10 7      .....A,value

stack
0 1 2 3 4 5 6 7 8  ...num
0
1 2 3 4 5
6 7 8
6 9
最后sta[0].parent=-1;  为根节点 即 6 为根节点。

这里给出的是索引从0开始的[0,n-1]
如果题目给出的是[1,n],可以减一回到[0,n-1]上。

这就是笛卡尔树的概念及建树过程。此题就可以把中序遍历1~n当成第一维权值出现的时间(满足中序遍历是1~n),把每个点的出现的时间(两个时间不要混)当做第二位权值建小根堆(因为在层次遍历出现时间越早越可能是根)。就可以O(n)建树然后遍历一遍求先序遍历了。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=300010;int s[maxn],a[maxn],b[maxn],x,n;struct tree{int fa,l,r,val;}t[maxn];inline int build(){int top=-1,k;for(int i=1;i<=n;i++){k=top;while(k>=0&&b[s[k]]>b[i])//栈中比当前元素大的都出栈 k--;if(k!=-1){//find it,栈中元素没有完全出栈,当前元素为栈顶元素的右孩子t[i].fa=s[k];t[s[k]].r=i;}if(k<top){//出栈的元素为当前元素的左孩子 t[s[k+1]].fa=i;t[i].l=s[k+1];}s[++k]=i;top=k;}t[s[0]].fa=-1;//遍历完成后的栈顶元素就是根return s[0];}inline void out(int x){if(x==-1) return ;printf("%d ",x);out(t[x].l);out(t[x].r);}int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[a[i]]=i;}for(int i=1;i<=n;i++){t[i].val=b[i];}for(int i=1;i<=n;i++)t[i].l=t[i].r=-1;x=build();out(x);return 0;}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 外阴部长了一个疙瘩有点痒怎么办 小孩打架被另一个小孩家人告怎么办 德保豆浆机有电但不工作怎么办 刚买的笔记本c盘不足怎么办 qq糖粘在喉咙气管里怎么办 穿上旗袍后感觉后腰处不平整怎么办 机打票给客人给错联怎么办?急 ps修证件照感觉不太立体怎么办 手机百度上下载的文档打不开怎么办 5岁宝宝乘飞机没带证件怎么办 网上订飞机票忘记订儿童票了怎么办 两岁宝宝对牛奶鸡蛋过敏了怎么办 两岁宝宝坐不住好跑怎么办 宝宝两岁多了不愿意坐小马桶怎么办 坐火车小孩拉屎在被子上怎么办 川航飞机票名字错了一个字怎么办 胜战本领怎么看走向战场怎么办 数数字油画你的颜料干了怎么办? 数字油画涂颜料涂错了怎么办 绝地求生模拟器注册已达上限怎么办 孕妇把番茄和虾一起吃了怎么办 4岁宝贝吃了玩具小电池怎么办 微信使用零钱需完善实名信息怎么办 两岁宝宝刷牙不会吐水怎么办 孩子牙龈上长了小牙怎么办 供暖公司未供暖却收取供暖费怎么办 两岁宝宝认知和语言能力低怎么办 蜡笔同步被对方发现删掉的怎么办 微信时间和手机时间不同步怎么办 孩子们家乡爱画美丽的也自己怎么办 娃把豆豆弄进鼻孔了怎么办 20岁了不知道自己该干什么怎么办 遇到一个新手买家恶意拍下怎么办 淘宝卖螃蟹有什么要求美工怎么办 淘宝衣服吊牌剪了想退货怎么办修 用图片在淘宝搜衣服搜不到怎么办 汽车黑塑料水砂纸磨的不平怎么办 sat报名要你填10位电话怎么办 手绘板连接电脑绘画有点迟钝怎么办 走路不小心滑了一下特尴尬怎么办 小孩子头撞了头发长不出来怎么办