Codefroces #353(Div.2) Tree Construction

今天模拟了一场CF比赛第四题没有做出来,赛后想了好久才想出来了,题意是给你n个互不相等的数,按照所给的数建立一个二叉排序树,要求输出n-1个数,从输入的第二个数开始所有数的父节点。这题咋一看要建立一个二叉排序树,然后查找结点的父节点,但是仔细想下就会发现还是有问题的,假如给出的数据建立的是一颗只有左子树或者只有右子树的二叉排序数,查找的时间复杂度为O(n*n),而题目中的n<100000,这显然会超时,这种方法就放弃了。

然后又自己写了一些数据在纸上画了下,分析发现一个数的父节点一定是在该节点之前出现并且大于value[n]且最接近value[n],或者小于value[n]也最接近于value[n],一定是这两种中的一种,那么问题又来了,到底是哪一种呢?继续进行分析,要分为三种情况分析:

  1. 假设当前节点k之前没有大于当前节点的值,此时当前节点的父节点为小于value[k]并且最接近于value[k],并且我们要标记小于value[k]并且最接近于value[k]的值有右子树,如下图1所示。
  2. 假设当前节点k之前没有小于当前节点的值,此时当前节点的父节点为大于value[k]并且最接近于value[k],并且我们要标记大于value[k]并且最接近于value[k]的值有做子树,入下图2所示。
1 图2
3 . 最后一种情况就是两种可能都出现,这时我们就要用到前面所记录的一些节点是否有左、右子树这个条件了,如果k节点中小于value[k]最接近于value[k]的值没有右子树那么这个数就是value[k]的父节点,否则看大于value[k]最接近于value[k]的值有没有左子树,如果没有则这个数的左子树就是value[k],以上两种情况一定有一种满足题意!

第一次RE了,因为标记每个出现的节点的左、右子树时节点的权值是整型,后来改用map过了,注意因为n<100000,所以如果每次直接暴力找第一个大于这个数的值的时候时间复杂度为O(n*n),显然不行,就必须用到set容器来解决这个问题,set自带二分查找函数。以上就是我对于这题的看法。
#include <iostream>
#include <cstdio>
#include <set>
#include <map>
#include <cstring>
using namespace std;
set<int>s;
set<int>::iterator it;
map<int, int>lchild;
map<int, int>rchild;
const int N = 100005;
int data[N];
int result[N];

int main()
{
    int n;
    while(cin>>n)
    {
        s.clear();
        lchild.clear();
        rchild.clear();
        for(int i=0; i<n ;i++)
            cin>>data[i];
        s.insert(data[0]);
        for(int i=1; i<n; i++)
        {
            int MIN, MAX;
            it = s.lower_bound(data[i]);
            if(it==s.end())
            {
                it--;
                result[i] = *it;
                rchild[*it] = 1;
            }
            else if(it == s.begin())
            {
                result[i] = *it;
                lchild[*it] = 1;
            }
            else
            {
                MAX = *it;
                MIN = *(--it);
                if(!rchild[MIN])
                {
                    rchild[MIN] = 1;
                    result[i] = MIN;
                }
                else
                {
                    lchild[MAX] = 1;
                    result[i] = MAX;
                }
            }
            s.insert(data[i]);
        }
        for(int i=1; i<n; i++)
            cout<<result[i]<<" ";
        cout<<endl;
    }
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值