【CF675D】Tree Construction

题目大意:给定一个有 N 个数组成的序列,在此基础上构建一棵二叉排序树,求每个节点(根节点除外)的父节点的编号是多少。

题解:首先,根据二叉排序树的不稳定性,直接模拟构建二叉排序树肯定会超时,因此需要用其他的数据结构来模拟 BST。在这里可以用平衡树来模拟,即:用一个 \(set\) 来维护这 N 个序列,因为平衡树的旋转功能使得父节点会发生改变,所以需要另外记录下对应的 BST 中,每个节点“本应该”的孩子是谁,即:用两个 \(map\) 来记录下每个节点对应的左右孩子即可。

引理1:BST 的构建是在原树构架的基础上进行的,即:未插入节点前的树中的节点在插入节点之后的相对位置不会发生改变。
引理2:在插入新节点时,该节点一定被插入在其前驱的右孩子或后继的左孩子的位置。
证明过程可以分以下几个步骤:

  1. 证明不可能出现前驱的右孩子和后继的左孩子均有节点的情况。
  2. 证明不可能出现前驱没有右孩子且后继没有左孩子的情况。
  3. 证明前驱和后继的 LCA 应该是这二者之一。

代码如下

#include <bits/stdc++.h>
using namespace std;

int n,val;
set<int> s;
map<int,int> ls,rs;
void solve(){
	scanf("%d",&val);
	s.insert(val);
	for(int i=1;i<n;i++){
		scanf("%d",&val);
		auto it=s.upper_bound(val);
		if(it!=s.end()&&ls.find(*it)==ls.end()){
			ls[*it]=val;
			printf("%d",*it);
		}else{
			--it;
			rs[*it]=val;
			printf("%d",*it);
		}
		putchar(i==n-1?'\n':' ');
		s.insert(val);
	}
}

int main(){
	scanf("%d",&n);
	solve();
	return 0;
}
posted @ 2018-12-02 21:01  shellpicker  阅读(191)  评论(0编辑  收藏  举报