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所示。
![](https://img-blog.csdn.net/20160524094330959)
图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自带二分查找函数。以上就是我对于这题的看法。
然后又自己写了一些数据在纸上画了下,分析发现一个数的父节点一定是在该节点之前出现并且大于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 命令特殊用法
- You must SET PASSWORD before executing this statement的解决方法
- 批处理 Set 命令详解 让你理解set命令第1/2页
- ASP中set与dim的区别(自己的理解)
- 深入C#中get与set的详解
- 浅析STL中的常用算法
- STL区间成员函数及区间算法总结
- sql Set IDENTITY_INSERT的用法
- set_include_path在win和linux下的区别
- jquery中常用的SET和GET
- c++ STL容器总结之:vertor与list的应用
- C++在成员函数中使用STL的find_if函数实例
- 大家注意vector, list, set, map成员函数erase
- 基于SQL中SET与SELECT赋值的区别详解
- mysql之set与enum的介绍
- php set_magic_quotes_runtime() 函数过时解决方法
- MySQL的FIND_IN_SET函数使用方法分享
- .net get set用法小结第1/3页
- mysqli_set_charset和SET NAMES使用抉择及优劣分析
- asp.net get set用法第1/2页