Codeforces 675D. Tree Construction(二叉搜索树性质)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jerry99s/article/details/86580070

题目: 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;
}

猜你喜欢

转载自blog.csdn.net/jerry99s/article/details/86580070