【CF 675D Tree Construction】BST
题目链接:http://codeforces.com/problemset/problem/675/D
题意:给一个由n个互异整数组成的序列a[],模拟BST的插入过程,依次输出每插入一个元素a[i]后a[i]的父节点。
数据范围:n [2, 10^5]
思路:直接模拟一般的BST而不维护平衡性的话,有可能会出现极度不平衡甚至退化的情况,复杂度会从O(nlogn)上升到O(n^2)。因此要用平衡二叉树。
可以利用STL中的set容器,但对于题目所要找的“父节点”,set并不提供接口。这时就要考察BST的一些性质推导出解法。
回顾二叉树的中序遍历,对节点prev的直接后继succ的定位操作分两种情况。注意等价BST的“上下可变,左右不乱”的性质,不论是否进行了等价变换,中序遍历序列中任意两个互为直接前驱和直接后继的元素,其层次关系必然为如下两种之一:

1. succ层次更深
=> 由顺序性,succ必为prev的右子树中的节点,故prev的右子树必非空;
且由“直接性”,succ的左孩子必为空。
对于v小于全局最小值的边界情况,prev及其左子树为空。
2. prev层次更深
=> 由顺序性,prev必为succ的左子树中的节点,故succ的左子树必非空;
且由“直接性”,prev的右孩子必为空。
对于v大于全局最大值的边界情况,succ及其右子树为空。
对于一个新的待插入的节点v,我们在当前BST的中序遍历序列 s 中进行二分查找,得到应插入的位置的后继元素的位置succ(“大于v的第一个元素,即upper_bound”),然后得到prev=succ-1。为了保证BST的顺序性,v必然要插在prev和succ之间。
从树的结构上看,可以插在标有“必为空”的位置,它恰好介于prev和succ之间,顺序性必然得到保证。具体地,即“succ和prev中更深的那个”,1、2两种情况分别对应succ和prev。如何确定是哪种情况呢?
我们回到对这两种情况的描述上:刚刚所做的推导是否可逆呢?如果可逆,那么我们可以通过判断succ或prev的左右孩子是否为空就可以得知是哪种情况。
分析发现,确实可逆:
1. succ的左孩子为空 => 由顺序性,prev必为succ的祖先 => succ层次更深。
2. prev的右孩子为空 => 由顺序性,succ必为prev的祖先 => prev层次更深。
到此,可以着手设计算法了。首先用set维护平衡二叉树,每次插入节点v前,调用set的lower_bound(或upper_bound,元素互异故二者无差别) 得到“大于v的第一个元素”,即插入v后v的直接后继,记录为迭代器succ。然后得到succ的直接前驱的迭代器prev = succ - 1。
对于左右孩子情况的记录,我没有想到方法,CF题解给出的是维护两个map<int, int>left, right,left记录节点对<v, lc>,right记录节点对<v, rc>。每次插入前通过判断left[succ]和right[prev]是否为空来判断父节点是谁,以及v作为左孩子还是右孩子插入,更新map。
其实这两种情况是对立的,因此一次判断就可确定属于哪种。
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
using namespace std;
const int MAX_N = ; int n;
struct Node
{
int d;
int lc, rc;
Node(){}
Node(int d):d(d), lc(-), rc(-){}
}nodes[MAX_N]; int a[MAX_N]; int main()
{
while(~scanf("%d", &n)){
for(int i=; i<n; i++){
scanf("%d", &a[i]);
}
set<int> s;
map<int, int> left;//<节点,左孩子>
map<int, int> right; //<节点,右孩子>
int res;
s.insert(a[]);
for(int i=; i<n; i++){
set<int>::iterator pos = s.lower_bound(a[i]);//直接后继
if(pos != s.end() && left.count(*pos)==){//后继没有左孩子,插到后继的左孩子位置
res = *pos;
left[*pos] = a[i];
}else{//后继有左孩子,或没有后继,插到前驱的右孩子位置
pos--;
res = *pos;
right[*pos] = a[i];
}
printf("%d ", res);
s.insert(a[i]);
}
printf("\n");
}
return ;
}
p.s: CF题解的代码好优美,学习了。
【CF 675D Tree Construction】BST的更多相关文章
- CF 675D——Tree Construction——————【二叉搜索树、STL】
D. Tree Construction time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- B. Lost Number【CF交互题 暴力】
B. Lost Number[CF交互题 暴力] This is an interactive problem. Remember to flush your output while communi ...
- 3.26-3.31【cf补题+其他】
计蒜客)翻硬币 //暴力匹配 #include<cstdio> #include<cstring> #define CLR(a, b) memset((a), (b), s ...
- 【Binary Search Tree Iterator 】cpp
题目: Implement an iterator over a binary search tree (BST). Your iterator will be initialized with th ...
- 【cf补题记录】Codeforces Round #608 (Div. 2)
比赛传送门 再次改下写博客的格式,以锻炼自己码字能力 A. Suits 题意:有四种材料,第一套西装需要 \(a\).\(d\) 各一件,卖 \(e\) 块:第二套西装需要 \(b\).\(c\).\ ...
- Codeforces 675D Tree Construction Splay伸展树
链接:https://codeforces.com/problemset/problem/675/D 题意: 给一个二叉搜索树,一开始为空,不断插入数字,每次插入之后,询问他的父亲节点的权值 题解: ...
- 【Cf Edu #47 F】Dominant Indices(长链剖分)
要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...
- 【Count Complete Tree Nodes】cpp
题目: Given a complete binary tree, count the number of nodes. Definition of a complete binary tree fr ...
- codeforces 675D Tree Construction set
转自:http://blog.csdn.net/qwb492859377/article/details/51447350 #include <stdio.h> #include < ...
随机推荐
- 如何在程序中调用Caffe做图像分类
Caffe是目前深度学习比较优秀好用的一个开源库,采样c++和CUDA实现,具有速度快,模型定义方便等优点.学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用Caffe做图像分类没有直接的 ...
- 【转】多核CPU运行模式
多核CPU运行模式主要有以下三种: •非对称多处理(Asymmetric multiprocessing,AMP)——每个CPU内核运行一个独立的操作系统或同一操作系统的独立实例(instantiat ...
- 分析NTFS文件系统得到特定文件的内容
找某一个文件的内容(如要读取文件D:\dir\dir2\text.txt,详细过程例如以下: (1)读取分区表/分区链表信息,找到磁盘F的起始扇区. (2)读取D盘的第一个扇区(分区的BOOTSETO ...
- LR选择哪种方式录制
LR选择哪种方式录制,有以下考虑原则: 1.基于浏览器的应用程序推荐使用HTML-basic script方式录制 2.不是基于浏览器的应用程序推荐使用URL-basic script方式录制 3.如 ...
- vue 单页面应用实战
1. 为什么要 SPA? SPA: 就是俗称的单页应用(Single Page Web Application). 在移动端,特别是 hybrid 方式的H5应用中,性能问题一直是痛点. 使用 SPA ...
- java中数据流的简单介绍
java中的I/O操作主要是基于数据流进行操作的,数据流表示了字符或者字节的流动序列. java.io是数据流操作的主要软件包 java.nio是对块传输进行的支持 数据流基本概念 “流是磁盘或其它外 ...
- Spring 反转控制(IOC) 依赖注入(DI)
简单的理解: 之前是我为了完成业务A 需要某个对象B的支持 那么我在这个业务A中就会创建一个对象B使用,说白了就是我根据需求来控制对象B, 而spring的ioc把对象B的控制权从业务A手中拿到自己手 ...
- 2016-XCTF Final-Richman
抽时间将XCTF Final中Richman这个题总结了下.题目及ida idb所在的链接在:http://files.cnblogs.com/files/wangaohui/richman-blog ...
- 19. Crontab
一.Crontab 的使用 1.crontab 命令参数: -e 编辑该用户的计时器设置 -l 列出该用户的计时器设置 -r 删除该用户的计时器设置-u<用户名称> 指定要设定计时器的 ...
- .net批量删除和添加
往页面上拖一个GridView,设置好数据源,并为GridView添加一个模板列,往模板列里添加一个chekcbox,比如下面的代码 <asp:GridView ID="GridVie ...