Loj #2324. 「清华集训 2017」小 Y 和二叉树
Loj #2324. 「清华集训 2017」小 Y 和二叉树
小Y是一个心灵手巧的OIer,她有许多二叉树模型。
小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上,树根在最上面,左右子树分别在树根的左下方与右下方,且他们也都满足
这样的悬挂规则。为了让这个模型更加美观,小Y选择了一种让这棵二叉树的中序遍历序列最小的悬挂方法。所谓中序遍历最小,就是指中序遍历的结点编号序列的字典
序最小。
一天,这个模型不小心被掉在了地上,幸运的是,所有结点和边都没摔坏,但是她想不起这个模型原来是怎么悬挂的了,也就是说:她想不起来树根节点的编号了。
小Y最近忙于准备清华集训,所以没太多时间处理别的事情,她只好找到同样心灵手巧的你帮忙复原她的二叉树模型。
给定小Y的二叉树模型,结点的编号为 \(1\) ~ \(n\) ,你需要给出其可能的最小的中序遍历,方便小Y更快的摆好她的模型。
输入格式
第一行为一个正整数 \(n\) ,表示点的个数。
后接 \(n\) 行,每行若干个整数:
第 \(i+1\) 行的第一个整数为 \(k_i\) ,表示编号为 \(i\) 的结点的度数,后接 \(k_i\) 个整数 \(a_{i,j}\) ,表示编号为 \(i\) 的结点与编号为 \(a_{i,j}\) 的结
点之间有一条边。
同一行输入的相邻两个元素之间,用恰好一个空格隔开。
输出格式
输出共一行, \(n\) 个整数,表示字典序最小的中序遍历。
数据范围与提示
\(n\leq 10^6\)
假设我们知道了最优答案下的根,那么答案就很好求了。
设\(mn_i\)表示\(i\)的子树的中序遍历得到第一个点。我们可以发现,\(mn_i\)就是\(i\)子树中度数\(\leq 2\)的子节点中最小的那个。然后我们就递归:如果一个点有两个儿子,就优先走\(mn\)值小的那个;如果只有一个儿子,就要判断儿子的\(mn\)值是否比自己的值大来判断将儿子放在左边还是右边。
难点就是找根。很容易发现,答案的第一位一定是度数\(\leq 2\)的节点中最小的那个。然后我们从这个点开始递归,找到最终答案下的根。我们先找到最小的点,设为\(g\)。然后以\(g\)为根,求出\(mn\)数组。接着就是分情况讨论:
假设当前处理\(v\)节点。默认与\(v\)相邻的还没有访问到的点为\(v\)的儿子。
- 情况1:
假设\(v\)只有一个儿子\(sn_1\),若 \(sn_1\leq mn_{sn_1}\) 则 \(sn_1\) 就作为\(v\)的父亲,递归\(sn_1\);否则\(v\)就是最终的根。
如果\(sn_1\)不作为\(v\)的父亲,那么最终答案里,\(v\)过了就是\(mn_{sn_1}\);反之\(v\)过了就是\(sn_1\)。所以这个贪心是正确的。
- 情况2:
假设\(v\)有两个儿子\(sn_1\),\(sn_2\)(不妨设\(mn_{sn_1}<mn_{sn_2}\))。那么将\(sn_1\)作为右儿子,\(sn_2\)作为父亲,递归\(sn_2\)。
#include<bits/stdc++.h>
#define ll long long
#define N 1000005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n;
int r[N];
struct road {
int to,nxt;
}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
vector<int>ans;
int rt;
bool vis[N];
int mn[N];
void Get_mn(int v,int fr) {
if(r[v]<3) mn[v]=v;
else mn[v]=1e9;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(to==fr) continue ;
Get_mn(to,v);
mn[v]=min(mn[v],mn[to]);
}
}
int RT;
void Find_rt(int v,int fr) {
int sn1=0,sn2=0;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(to==fr) continue ;
if(!sn1) sn1=s[i].to;
else sn2=s[i].to;
}
if(!sn1) {RT=v;return ;}
if(!sn2) {
if(sn1<=mn[sn1]) Find_rt(sn1,v);
else {RT=v;return ;}
} else {
if(mn[sn1]>mn[sn2]) swap(sn1,sn2);
Find_rt(sn2,v);
}
}
void Print(int v,int fr) {
int sn1=0,sn2=0;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(to==fr) continue ;
if(!sn1) sn1=to;
else sn2=to;
}
if(mn[sn1]>mn[sn2]) swap(sn1,sn2);
if(!sn2&&mn[sn1]>v) swap(sn1,sn2);
if(sn1) Print(sn1,v);
cout<<v<<" ";
if(sn2) Print(sn2,v);
}
int main() {
mn[0]=1e9;
n=Get();
for(int i=1;i<=n;i++) {
int k=Get();
r[i]=k;
while(k--) {
int a=Get();
add(i,a);
}
}
rt=1e9;
for(int i=1;i<=n;i++) if(r[i]!=3) rt=min(rt,i);
Get_mn(rt,0);
Find_rt(rt,0);
Get_mn(RT,0);
Print(RT,0);
return 0;
}
Loj #2324. 「清华集训 2017」小 Y 和二叉树的更多相关文章
- [LOJ#2324]「清华集训 2017」小Y和二叉树
[LOJ#2324]「清华集训 2017」小Y和二叉树 试题描述 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙 ...
- [LOJ#2323]「清华集训 2017」小Y和地铁
[LOJ#2323]「清华集训 2017」小Y和地铁 试题描述 小Y是一个爱好旅行的OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的 ...
- loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主
#2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 "A fight? Co ...
- loj2324 「清华集训 2017」小 Y 和二叉树
https://loj.ac/problem/2324 太智障,一开始以为中序遍历的第一个点一定是一个叶子,想了个贪心.然而,手算了一下,第一个点都过不了啊. input 5 2 3 4 1 3 3 ...
- LOJ2324. 「清华集训 2017」小 Y 和二叉树【贪心】【DP】【思维】【好】
LINK 思路 首先贪新的思路是处理出以一个节点为根所有儿子的子树中中序遍历起始节点最小是多少 然后这个可以两次dfs来DP处理 然后就试图确定中序遍历的第一个节点 一定是siz<=2的编号最小 ...
- LOJ2324「清华集训 2017」小Y和二叉树
题目链接 瞎jb贪一发就过了.首先度数<=2且编号最小的点一定是中序遍历最靠前的点,我们从这个点开始dfs一遍算出子树中度数<=2且编号最小的点记为\(f(i)\),然后从这个点开始一步一 ...
- LibreOJ #2325. 「清华集训 2017」小Y和恐怖的奴隶主(矩阵快速幂优化DP)
哇这题剧毒,卡了好久常数才过T_T 设$f(i,s)$为到第$i$轮攻击,怪物状态为$s$时对boss的期望伤害,$sum$为状态$s$所表示的怪物个数,得到朴素的DP方程$f(i,s)=\sum \ ...
- 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法
题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...
- LOJ2325. 「清华集训 2017」小 Y 和恐怖的奴隶主【矩阵快速幂优化DP】【倍增优化】
LINK 思路 首先是考虑怎么设计dp的状态 发现奴隶主的顺序没有影响,只有生命和个数有影响,所以就可以把每个生命值的奴隶主有多少压缩成状态就可以了 然后发现无论是什么时候一个状态到另一个状态的转移都 ...
随机推荐
- 前端笔记之jQuery(下)事件&节点操作&净位置&拖拽&页面卷动值&遍历JSON
一.监听事件大全 1.1 JavaScript事件 onblur 元素失去焦点 onchange 用户改变域的内容 onclick 鼠标点击某个对象 ondblclick 鼠标双击某个对象 onfoc ...
- Docker折腾手记-安装
安装 docker红的发紫,所以博主耳闻这么久,也要来折腾折腾了 研究不多,个人目前认为docker给我们带来了以下好处 开发机器因为开发原因,需要配置各种各校的环境,繁琐且耗费资源.配来配去还容易环 ...
- 【c#】RabbitMQ学习文档(一)Hello World
一.简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到邮筒之时,你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人的手里,不 ...
- Android事件机制之二:onTouch详解
<Android事件机制之一:事件传递和消费>一文总结了Android中的事件传递和消费机制. 在其中对OntachEvent中的总结中,不是很具体.本文将主要对onTach进行总结. o ...
- PE知识复习之PE的绑定导入表
PE知识复习之PE的绑定导入表 一丶简介 根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题. PE在加载前 INT IAT表都指向一个名称 ...
- hadoop2 datanode启动异常解决步骤
1.datanode起不来2016-11-25 09:46:43,685 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Invalid d ...
- Perl进程间数据共享
本文介绍的Perl进程间数据共享内容主体来自于<Pro Perl>的第21章. IPC简介 通过fork创建多个子进程时,进程间的数据共享是个大问题,要么建立一个进程间通信的通道,要么找到 ...
- 【深度学习系列】用PaddlePaddle进行车牌识别(二)
上节我们讲了第一部分,如何用生成简易的车牌,这节课中我们会用PaddlePaddle来识别生成的车牌. 数据读取 在上一节生成车牌时,我们可以分别生成训练数据和测试数据,方法如下(完整代码在这里): ...
- 用C#写的一个OA类的APP, ios、Android都能跑,有源代码
这是一个用C#写的OA类APP,功能包含请假.报销.部门管理.签到.IM.文件上传等功能 话不多说,先看视频 视频地址:http://v.youku.com/v_show/id_XMzUwMjQ1Mz ...
- SQL Server表名为添加中括号[]执行出错
执行SQL语句: Update Check Set EOBTypeID=102 where E0BID='123344' 结果竟然报错,给表名添加中括号,写成这样: Update [Check] Se ...