http://www.codeforces.com/problemset/problem/675/D
给定一段数列(数列中每个数值不同),按顺序插入到一棵初始为空的排序二叉树中。求树的最终形态(每个点的父亲)。2<=n<=1e5
这种不难但是需要一点数学思维的题目很能锻炼人思维的灵活性,拿来考察状态是很不错的。
首先直接模拟肯定会被卡,这一点应该有充分的警觉性。
我们需要注意bst的中序遍历性质。
首先,假设x结点被插入为y结点的儿子,则x与y在中序遍历序列中肯定相邻。
既然bst的中序遍历序列递增,所以y一定是x的前驱或后继。
若y<x,则x是y的右孩子,否则x是y的左孩子。
那么,y到底是x的前驱还是后继呢?x是y的左孩子还是右孩子呢?
首先x无前驱或后继的情况最简单。
否则,设有前驱p,后继s,假设p的右孩子和s的左孩子都为空,
显然p<s。
若s和p是祖孙关系(它们的LCA是s或p):
若s是p的祖先,则p在s的左子树上,矛盾。
同理,p也不可能是s的祖先。
若它们有某共同祖先g,则一定有p<g<s,与p和s是前驱、后继矛盾。
故p右孩子和s左孩子至少有一个为空。
再假设p右孩子和s左孩子都不为空,则必然存在m,p<m<s,也矛盾。
故s和p有且只有一个地方能放孩子。
然后用set和map搞一下就行了。
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<set> 8 #include<map> 9 using namespace std; 10 11 set<int> a; 12 set<int> :: iterator p; 13 map <int, pair<int,int> >hash; 14 15 int main() 16 { 17 int n,i,x,ans; 18 cin >> n; 19 scanf("%d", &x); 20 a.insert(x); 21 for(i = 2; i<=n; i++) { 22 scanf("%d", &x); 23 p = a.lower_bound(x); 24 if(p==a.begin()) { 25 ans = *p; 26 hash[*p].first = 1; 27 } 28 else if(p==a.end()) { 29 p--; 30 ans = *p; 31 hash[*p].second = 1; 32 } 33 else { 34 if(!hash[*p].first) { 35 ans = *p; 36 hash[*p].first = 1; 37 } 38 else { 39 ans = *(--p); 40 hash[*p].second = 1; 41 } 42 } 43 a.insert(x); 44 printf("%d ", ans); 45 } 46 return 0; 47 }