题目: http://codeforces.com/problemset/problem/675/D
题意:
n个不同的数,依次按要求插入二叉搜索树中,输出每个数的父节点是谁。
要求如下:
1.第一个数是根节点;
2.插入a[i]时,从根节点开始向下走,若当前节点的数<a[i],向右走,否则向右走,若走不下去则生成新节点并赋权值为a[i]。
分析:
性质①:
a[i]要么是a[1] ~a[i-1]中大于a[i]的最小的数的儿子;
要么是a[1] ~a[i-1]中小于a[i]的最大的数的儿子。
证明(反证法):
首先观察这颗二叉搜索树的中序遍历,是单调递增的。
假设a[i]的父亲不是a[1] ~a[i-1]中大于a[i]的最小的数,而是第二小的数,如下图左侧所示。
其中序遍历为:a[i],A,a2
由于字数A中的数肯定在a[i]之后出现,所以不包含a1
因为其中序遍历是递增的,所以应该为a[i],A,a1,a2,矛盾。
另外一种情况同理可证。
性质②:
对于a1和b1,后出现的那个为a[i]的父亲。
证明略。
注意:如果set::iterator iter==set.end(),那么iter–会出问题!
代码:
//jerry99
#include <bits/stdc++.h>
using namespace std;
typedef long long llong;
const int tmax=1e5+5;
int n,a[tmax];
map<int,int> MM;
set<int> SET;
set<int>::iterator iter,iter2;
int main()
{
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
MM[a[i]]=i;
}
SET.insert(a[1]);
for(i=2;i<=n;i++)
{
SET.insert(a[i]);
iter=SET.lower_bound(a[i]);
iter2=SET.upper_bound(a[i]);
if(iter==SET.begin())
{
printf("%d ",*iter2);
continue;
}
iter--;
if(iter2==SET.end())
{
printf("%d ",*(iter));
continue;
}
if(MM[*iter]>MM[*iter2]) printf("%d ",*iter);
else printf("%d ",*iter2);
}
return 0;
}