【NOIP模拟考三】线段树/ST表 day2 second 二叉树
2017-08-19 18:14
330 查看
题目描述
给定一棵二叉树,节点标号从1到n。在不改变其中序遍历的情况下,请改变树的结构,使得这棵二叉树的先序遍历(前序遍历)字典序最小。
输入
第一行一个整数n,表示二叉树的节点数。接下来n行,每行两个整数。第i行的两个整数表示编号为i的节点的左儿子和右儿子的编号(不存在即为0)。
输出
输出一行n个整数,表示不改变中序遍历的情况下字典序最小的前序遍历序列。
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)5 5 4 0 0 2 1 0 0 0 0
样例输出
1 2 3 5 4
提示
1 3 N/A
2 4 N/A
3 10 N/A
4 100 树为一条链,且只存在右儿子关系。
5 1000 给出的树满足排序二叉树的性质。即任意一个节点
6 100000 左子树中所有值<该节点<右子树中所有值。
7 65535 满二叉树
8 100000 N/A
9 100000 N/A
看那水题一道两道三道连成线!
咳咳,我还是要填坑的。。。
考试时这道题还是想了很久,想过各种诡异的方法,比如LCA啦、平衡树啦、暴力啊。。。什么都有,后来才恍然大悟——这题好水。。。
我们要让中序遍历的顺序不变,却不知道中序遍历的结果是什么,怎么可以呢,是吧……所以第一步应该中序遍历!
我们就举样例的例子吧!
好久没有看到图片了,是不是很激动?
很容易发现,我们只需要让根最小就是最优的,那么我们很显然要1当根。其次,显然的,根的左儿子最小就最好,于是我们把2当做1的左儿子,但是,尽管样例是可以的,却并不代表所有数据都可以,别忘了中序遍历的限制!
很容易发现,只要是中序遍历根左边的,就可以当成是左儿子,那么我们可以在根左边的中选出一个最小的来当根的左儿子,然后同样的在右边选一个最小的当右儿子,用线段树维护区间最小值就好了啦……(当然ST表也是可以的……)
所以样例就很容易解释了——先选1,在左边选择最小的2,2没有左边,于是在右边选择最小的3,3也没有左边,于是在右边选择最小的5,这时1的左子树完毕,在右边选择最小的4,整棵树完毕。按遍历顺序依次输出:
1 2 3 5 4 PS:这道题虽然是求先序遍历,其实完全不需要再建一棵树,只要假想有那么一棵树就可以了……
好了,一如既往的代码……
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100005 int n,ls ,rs ,fa ,r; int mid ,wz ,tim; void dfs(int r) { if(ls[r]) dfs(ls[r]); mid[++tim]=r; wz[r]=tim; if(rs[r]) dfs(rs[r]); } struct ST { int l,r,minn; }s[4*N-15]; void make(int l,int r,int q) { s[q].l=l;s[q].r=r; if(l<r) { int mid=(l+r)>>1; make(l,mid,q<<1); make(mid+1,r,q<<1|1); } } void insert(int a,int k,int q) { if(s[q].l==k&&s[q].r==k) { s[q].minn=a; return; } if(k>((s[q].l+s[q].r)>>1)) insert(a,k,q<<1|1); else insert(a,k,q<<1); s[q].minn=min(s[q<<1].minn,s[q<<1|1].minn); } int minn(int l,int r,int q) { if(l==s[q].l&&r==s[q].r) return s[q].minn; int mid=(s[q].l+s[q].r)>>1; if(r<=mid) return minn(l,r,q<<1); if(l>mid) dbdb return minn(l,r,q<<1|1); return min(minn(l,mid,q<<1),minn(mid+1,r,q<<1|1)); } void getans(int l,int r) { if(l>r) return; int now=minn(l,r,1); int p=wz[now]; printf(" %d",now); getans(l,p-1); getans(p+1,r); } int main() { //freopen("bitree.in","r",stdin); //freopen("bitree.out","w",stdout); scanf("%d",&n); make(1,n,1); for(int i=1;i<=n;i++) { scanf("%d%d",&ls[i],&rs[i]); if(ls[i]) fa[ls[i]]=i; if(rs[i]) fa[rs[i]]=i; } for(int i=1;i<=n;i++) if(!fa[i]) { r=i; break; } dfs(r); for(int i=1;i<=n;i++) insert(mid[i],i,1); printf("1"); getans(1,wz[1]-1); getans(wz[1]+1,n); }
相关文章推荐
- 【NOIP模拟考一】 贪心 second 排座椅(seat.cpp)
- NOIP2017 模拟考试 day2 2017.10.07
- 计蒜客NOIP提高组模拟Day2,Pro1蒜头君的兔子
- 【NOIP模拟考三】无向图的桥 day1 second 荒岛野人
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径
- 10.26最后的模拟DAY2 改造二叉树[中序遍历+严格递增的最长不下降子序列]
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)总结
- 洛谷 NOIP 模拟 DAY2
- 【20150905】NOIP模拟套题01 day2 题解 & 总结
- 【NOIP模拟考三】水资源 day2 first 序列计数
- {小结}NOIP2016提高A组模拟8.19(雅礼联考day2)
- 2017.8.19~8.20 noip 模拟 day2
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)公约数
- 【20150915】NOIP模拟套题02 day2 题解 & 总结
- NOIP模拟 17.8.14
- NOIP2015模拟3
- 【NOIP2017模拟】春思
- NOIP模拟20150904总结
- jzoj5341. 【NOIP2017模拟9.2A组】密州盛宴
- [NOIP2017模拟]构造