码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 675D Tree Construction

时间:2016-06-01 22:47:14      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:

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 }
View Code

 

 

codeforces 675D Tree Construction

标签:

原文地址:http://www.cnblogs.com/liuaohan/p/5551167.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!