P1377 [TJOI2011]树的序

题目描述

众所周知,二叉查找树的形态和键值的插入顺序密切相关。准确的讲:1、空树中加入一个键值\(k\),则变为只有一个结点的二叉查找树,此结点的键值即为\(k\);2、在非空树中插入一个键值\(k\),若\(k\)小于其根的键值,则在其左子树中插入\(k\),否则在其右子树中插入\(k\)。

我们将一棵二叉查找树的键值插入序列称为树的生成序列,现给出一个生成序列,求与其生成同样二叉查找树的所有生成序列中字典序最小的那个,其中,字典序关系是指对两个长度同为\(n\)的生成序列,先比较第一个插入键值,再比较第二个,依此类推。

输入输出格式

输入格式:

第一行,一个整数,\(n\),表示二叉查找树的结点个数。第二行,有\(n\)个正整数,\(k_1\)到\(k_n\),表示生成序列,简单起见,\(k_1\)~\(k_n\)为一个1到\(n\)的排列。

输出格式:

一行,\(n\)个正整数,为能够生成同样二叉查找数的所有生成序列中最小的。

说明

对于20%的数据,n ≤ 10。

对于50%的数据,n ≤ 100。

对于100%的数据,n ≤ 100,000。


先化简一下模型,我们把\(BST\)树建好,然后输出中序遍历即是答案。

然而,直接建\(BST\)是很容易退化成链的。

做过题目多的人可能听说过,这个叫笛卡尔树

笛卡尔树是一种既满足堆性质又满足二叉排序树性质的树。

方法一:普通笛卡尔树的建树方法

现在有一个序列按二叉排序树的关键字\(Key\)从小到大有序,序列中包含小跟堆的关键字\(Index\)关键字,在\(O(N)\)的时间建树。

按原数列顺序一个一个将节点加入笛卡尔树,可以确定一定是从链的右边向下找到一个\(Index\)大于这个点的节点,把这个节点位置占据,然后置让Ta当自己的左儿子即可。

用栈把最右边的链存下来,栈顶为右边最底的那个点,加入时边弹出边向上找,更新好位置关系后把自己存进栈即可。

code:

#include <cstdio>
#include <algorithm>
#define ls t[now].ch[0]
#define rs t[now].ch[1]
#define f t[now].par
const int N=100010;
struct node
{
int dat,index;
bool friend operator <(node n1,node n2)
{
return n1.dat<n2.dat;
}
}a[N];
struct BST
{
int ch[2],dat,index,par;//左右儿子,BST域,堆域,父亲
}t[N];
int tot=0,n,s[N];
void connect(int fa,int now,int typ)
{
f=fa;
t[fa].ch[typ]=now;
}
void dfs(int now)
{
if(!now) return;
printf("%d ",t[now].dat);
dfs(ls);
dfs(rs);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
a[i].index=i;
}
std::sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
int last=0;
while(tot&&t[s[tot]].index>a[i].index)
last=tot--;
t[i].dat=a[i].dat;
t[i].index=a[i].index;
connect(s[tot],i,1);
connect(i,s[last],0);
s[++tot]=i;
}
dfs(t[0].ch[1]);
return 0;
}

方法二:按堆性质自底向上建立。

这个方法好厉害,真的很强。

则如果两个点的\(Key\)在“当前”数值上的差最小,那么Ta俩一定有一条边。

按\(Index\)从大到小建立笛卡尔树,则对\(1\)-\(Index-1\)的点中,是不会有\(Index\)的儿子的。

用\(pre[i]\)与\(suc[i]\)分别存储\(Key\)为\(i\)的点在“当前”所相邻的前驱和后继。

每次处理完一个点,更新与它相连的“前驱”和“后继”,这对应了“当前”

注意到原数据为1到n的排列,可以用桶排,比较快。

Code:

#include <cstdio>
const int N=100010;
int a[N],b[N],L[N],R[N],pre[N],suc[N],n;
void dfs(int now)
{
if(!now) return;
printf("%d ",a[now]);
dfs(L[now]);dfs(R[now]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
b[a[i]]=i;
pre[i]=i-1,suc[i]=i+1;
}
for(int i=n;i>1;i--)
{
int pree=pre[a[i]],succ=suc[a[i]];
if(b[pree]>b[succ])
R[b[pree]]=i;
else
L[b[succ]]=i;
suc[pree]=succ;pre[succ]=pree;
}
dfs(1);
return 0;
}

2018.6.19

洛谷 P1377 [TJOI2011]树的序 解题报告的更多相关文章

  1. [洛谷 P1377] TJOI2011 树的序

    问题描述 众所周知,二叉查找树的形态和键值的插入顺序密切相关.准确的讲:1.空树中加入一个键值k,则变为只有一个结点的二叉查找树,此结点的键值即为k:2.在非空树中插入一个键值k,若k小于其根的键值, ...

  2. 单调队列优化O(N)建BST P1377 [TJOI2011]树的序

    洛谷 P1377 [TJOI2011]树的序 (单调队列优化建BST 链接 题意分析 本题思路很简单,根据题意,我们利用所给的Bst生成序将Bst建立起来,然后输出该BST的先序遍历即可: 但,如果我 ...

  3. 洛谷 P2323 [HNOI2006]公路修建问题 解题报告

    P2323 [HNOI2006]公路修建问题 题目描述 输入输出格式 输入格式: 在实际评测时,将只会有m-1行公路 输出格式: 思路: 二分答案 然后把每条能加的大边都加上,然后加小边 但在洛谷的题 ...

  4. Luogu P1377 [TJOI2011]树的序:离线nlogn建二叉搜索树

    题目链接:https://www.luogu.org/problemnew/show/P1377 题意: 有一棵n个节点的二叉搜索树. 给出它的插入序列,是一个1到n的排列. 问你使得树的形态相同的字 ...

  5. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

  6. 洛谷 P3157 [CQOI2011]动态逆序对 解题报告

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列\(A\),它的逆序对数定义为满足\(i<j\),且\(A_i>A_j\)的数对\((i,j)\)的个数.给\(1\)到\(n ...

  7. 洛谷 P3237 [HNOI2014]米特运输 解题报告

    P3237 [HNOI2014]米特运输 题目描述 米特是\(D\)星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题. \(D\)星上有 ...

  8. 洛谷 P2146 [NOI2015]软件包管理器 解题报告

    P2146 [NOI2015]软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软 ...

  9. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

随机推荐

  1. Android Notification的使用 - z

    http://blog.csdn.net/new_one_object/article/details/55511253 另,博主其它文章也很好  

  2. 20155323刘威良《网络对抗》Exp6 信息搜集与漏洞扫描

    20155323刘威良<网络对抗>Exp6 信息搜集与漏洞扫描 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 实践内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查 ...

  3. 【SP1811】LCS - Longest Common Substring

    [SP1811]LCS - Longest Common Substring 题面 洛谷 题解 建好后缀自动机后从初始状态沿着现在的边匹配, 如果失配则跳它的后缀链接,因为你跳后缀链接到达的\(End ...

  4. OLEDB数据源和目标组件

    在SSIS工程的开发过程中,OLEDB 数据源和目标组件是最常用的数据流组件.从功能上讲,OLEDB 数据源组件用于从OLEDB 提供者(Provider)中获取数据,传递给下游组件,OLEDB提供者 ...

  5. 4、Docker数据管理

    一.挂载类型 1.volumes Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes).保存数据的最佳方式. 使用场景:将容器中的数据持久化到宿主机,比如容器是my ...

  6. python 函数学习

    print dic.items() #[('a', 'hello'), ('c', 'you'), ('b', 'how')] print dic.iteritems() #<dictionar ...

  7. manjaro安装软件

    fcitx 安装以下包 fcitx-googlepinyin kcm-fcitx 安装了输入法之后,还要在/etc/profile或~/.xprofile里添加如下内容: export GTK_IM_ ...

  8. 使用devstack/pike部署多节点实验

    目录 第一步:安装Ubuntu16.04 server并以stack为用户名创建用户 第二步:安装git及相关配置 第三步:安装Open vSwitch 2.5.X 第四步:获取devstack脚本 ...

  9. 微软职位内部推荐-Software Engineer II-Search

    微软近期Open的职位: Do you want to work on a fast-cycle, high visibility, hardcore search team with ambitio ...

  10. 第二次Scrum meeting

    第二次Scrum meeting 任务及其要求: 成员 12.11 12.12 陈谋 完成Tags的爬取工作(已完成) stackoverflow的问题抽取 卢惠明 视频链接的挖掘和整理(未完成) 视 ...