您的位置:首页 > 其它

Codefroces #353(Div.2) Tree Construction

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

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

假设当前节点k之前没有大于当前节点的值,此时当前节点的父节点为小于value[k]并且最接近于value[k],并且我们要标记小于value[k]并且最接近于value[k]的值有右子树,如下图1所示。
假设当前节点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
;
int result
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  set STL