题目链接: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的更多相关文章

  1. CF 675D——Tree Construction——————【二叉搜索树、STL】

    D. Tree Construction time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  2. B. Lost Number【CF交互题 暴力】

    B. Lost Number[CF交互题 暴力] This is an interactive problem. Remember to flush your output while communi ...

  3. 3.26-3.31【cf补题+其他】

      计蒜客)翻硬币 //暴力匹配 #include<cstdio> #include<cstring> #define CLR(a, b) memset((a), (b), s ...

  4. 【Binary Search Tree Iterator 】cpp

    题目: Implement an iterator over a binary search tree (BST). Your iterator will be initialized with th ...

  5. 【cf补题记录】Codeforces Round #608 (Div. 2)

    比赛传送门 再次改下写博客的格式,以锻炼自己码字能力 A. Suits 题意:有四种材料,第一套西装需要 \(a\).\(d\) 各一件,卖 \(e\) 块:第二套西装需要 \(b\).\(c\).\ ...

  6. Codeforces 675D Tree Construction Splay伸展树

    链接:https://codeforces.com/problemset/problem/675/D 题意: 给一个二叉搜索树,一开始为空,不断插入数字,每次插入之后,询问他的父亲节点的权值 题解: ...

  7. 【Cf Edu #47 F】Dominant Indices(长链剖分)

    要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...

  8. 【Count Complete Tree Nodes】cpp

    题目: Given a complete binary tree, count the number of nodes. Definition of a complete binary tree fr ...

  9. codeforces 675D Tree Construction set

    转自:http://blog.csdn.net/qwb492859377/article/details/51447350 #include <stdio.h> #include < ...

随机推荐

  1. HDOJ-1016 Prime Ring Problem(DFS)

    http://acm.hdu.edu.cn/showproblem.php?pid=1016 题意:输入n,代表有一个包含n个节点的环,在环中的节点中填入1,2...n-1,n,要求填入的数与左边的数 ...

  2. python练习linux下创建路径

    #coding=utf-8 import os class MakeDirectory(): def mkdir(self,path): # 去除首位空格 path=path.strip() # 去除 ...

  3. ios 读取通讯录数据

    #import <Foundation/Foundation.h> @interface LoadingContactData : NSObject // 读取通讯录 + (Loading ...

  4. How to uninstall (remove) JAVA from OS X Lion

    Open terminal (Applications -> Utilities -> Terminal) To remove JVM enter folowing: sudo rm -r ...

  5. 使用Xshell连接Ubuntu

    使用Xshell连接Ubuntu Xshell是一个安全终端模拟软件,可以进行远程登录.我使用XShell的主要目的是在Windows环境下登录Linux终端进行编码,非常方便.本文简单介绍下它的使用 ...

  6. 整合 新浪 腾讯 人人 qq空间 分享地址

    function snsShare(snsId, title, content, image, url) { var snsUrl; // 新浪 腾讯 要申请appkey switch (snsId) ...

  7. Entity Framework中datetime2 to datetime转换错误

    datetime2 to datetime 报错. 因为EF中,DATETIME类型默认是datetime2,数据库默认是datetime. 解决方案: 1.改数据库字段类型为datetime2 2. ...

  8. Visual Studio 2013 Web开发、新增功能:“Browser Link”

    微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Server 2013. ...

  9. 百度地图API用法(传地址)

    网上找了很多都是没用的,非动态用法,最后在官网论坛才问到的 现在来一步一步教大家用 1 这是地址:   http://developer.baidu.com/map/ 选择web开发 先获取密钥   ...

  10. KMP与扩展KMP

    原文转自:http://www.cppblog.com/MatoNo1/archive/2011/04/17/144390.aspx KMP:给出两个字符串A(称为模板串)和B(称为子串),长度分别为 ...