原文链接 www.cnblogs.com/zhouzhendong/p/UOJ339.html

前言

好久没更博客了,前来更一发。

题解

首先,我们考虑一个子问题:给定根,求出最小中序遍历。

如果根节点有一个儿子,那么,我们需要比较根节点和 儿子的最小中序遍历的第一个元素,选择较优的一方放在前面。

如果根节点有两个儿子,那么,我们必然选择最小中序遍历较小的儿子放在左儿子。

由于所有节点编号互不相同,所以我们在比较两个部分的字典序时,只关注第一个元素的大小。

可以发现,一个有两个儿子的节点是不可能作为以它为根的子树的最小字典序的第一个元素的,接着,我们发现,除了这些节点之外的节点都可以作为最小字典序的第一个元素,构造方法如图所示:

所以我们将子树中这类节点编号的最小值较小的节点作为左子树即可。

然后我们考虑不定根的情况。

首先,我们关注最小字典序的第一元素,它一定是度数小于3的最小编号节点。我们以这个节点为根处理出每一个子树的最小字典序的第一个元素,并将左右儿子中字典序较小的一方放在左儿子。

我们将这个节点设为 x 。

如果 x 的度数为 2,那么,选择字典序较小的子树作为它的右子树,将其另一个子树的根的左儿子(对于这棵子树,我们就用之前提到的有根树的方式来解决),然后切除这条边,让这个子树的根取代 x ,并继续重复执行类似操作。

如果 x 的度数为 1,设 x 的儿子为 y。

如果 y 有儿子,那么,y、y 的左子树的最小字典序的第一个元素 都可能作为下一个元素,所以我们要取较优的一方:假设让 y 作为下一个元素,那么令最终构造方案中 y 的左儿子为 x,然后切除 x 与 y 之间的边,让 y 取代 x,并重复执行类似操作;如果选择 y 的左子树,那么就令 y 作为 x 的右儿子,并直接套用之前提到的有根树的解决方法来处理子树 y。

如果 y 只有一个儿子,那么,将 y 作为 x 的右儿子或者将 x 作为 y 的左儿子的效果完全相同,但是将 x 作为 y 的左儿子可以保留让 y 的儿子 z 作为 z 子树的中序遍历的最小元素的机会,所以我们选择将 x 作为 y 的左儿子。

P.S. 我觉得看题解说分讨不如直接看代码。。。。

代码

#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=1e6+5;
int n;
vector <int> e[N];
int mi[N];
int son[N][2];
void dfs(int x,int pre){
mi[x]=e[x].size()!=3?x:n+1;
for (auto y : e[x])
if (y!=pre){
dfs(y,x);
mi[x]=min(mi[x],mi[y]);
son[x][son[x][0]!=0]=y;
}
if (mi[son[x][0]]>mi[son[x][1]])
swap(son[x][0],son[x][1]);
}
vector <int> ans;
void calc(int x){
if (!x)
return;
if (son[x][0]&&son[x][1])
calc(son[x][0]),ans.pb(x),calc(son[x][1]);
else if (x<mi[son[x][0]])
ans.pb(x),calc(son[x][0]);
else
calc(son[x][0]),ans.pb(x);
}
void solve(int x){
ans.pb(x);
if (!son[x][0])
return;
if (son[x][1])
calc(son[x][0]),solve(son[x][1]);
else {
x=son[x][0];
if (x<=mi[x])
solve(x);
else
calc(x);
}
}
int main(){
n=read();
For(i,1,n){
int k=read();
while (k--)
e[i].pb(read());
}
int x=mi[0]=n+1;
For(i,1,n)
if (e[i].size()!=3)
x=min(x,i);
dfs(x,0);
solve(x);
for (auto i : ans)
printf("%d ",i);
return 0;
}

UOJ#339. 【清华集训2017】小 Y 和二叉树 贪心的更多相关文章

  1. [清华集训2017]小 Y 和地铁(神奇思路,搜索,剪枝,树状数组)

    世界上最不缺的就是好题. 首先考虑暴搜.(还有什么题是从这东西推到正解的……) 首先单独一个换乘站明显没用,只用考虑一对对的换乘站. 那么有八种情况:(从题解偷图)         然后大力枚举每个换 ...

  2. 【清华集训】小Y和地铁

    图已挂,前往luogu 题目: 小 $\rm Y$ 是一个爱好旅行的 $\rm OIer$.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁.她发现每条地铁线路可以看成平面上的一条 ...

  3. 清华集训2017D2T1 小 Y 和地铁(metro)

    题目:https://www.luogu.org/problem/show?pid=P4005 题意:一条线段,给定n个点(n<=44)其中每个点可能对应另外一个点.如果一个点有对应点,那么就要 ...

  4. 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)

    [UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...

  5. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

  6. loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主

    #2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较   题目描述 "A fight? Co ...

  7. [LOJ#2324]「清华集训 2017」小Y和二叉树

    [LOJ#2324]「清华集训 2017」小Y和二叉树 试题描述 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙 ...

  8. [LOJ#2323]「清华集训 2017」小Y和地铁

    [LOJ#2323]「清华集训 2017」小Y和地铁 试题描述 小Y是一个爱好旅行的OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的 ...

  9. 【luoguP4006 清华集训2017】小Y和二叉树

    题目描述 小 Y 是一个心灵手巧的 OIer,她有许多二叉树模型. 小 Y 的二叉树模型中,每个结点都具有一个编号,小 Y 把她最喜欢的一个二叉树模型挂在了墙上,树根在最上面,左右子树分别在树根的左下 ...

随机推荐

  1. atan、atanf、atanl、atan2、atan2f、atan2l

    很久不发博客了,今天在园中计算各种角,于是复习下fan正切函数 计算x的反正切值 (atan.atanf和 atanl) 或y/x 的反正切值 (atan2.atan2f和 atan2l).     ...

  2. thinkPHP中session()方法用法详解

    本文实例讲述了thinkPHP中session()方法用法.分享给大家供大家参考,具体如下: 系统提供了Session管理和操作的完善支持,全部操作可以通过一个内置的session函数完成. 用法 ? ...

  3. vs code 调试设置

    首先vs code 安装插件:Debugger for Chrome vscode 设置:点击调试按钮,然后调试面板界面再点击设置按钮,添加一个配置,选择环境为:chrome编辑器自动生成一个laun ...

  4. Struts框架笔记04_拦截器_标签库

    目录 1. Struts2的拦截器 1.1 拦截器概述 1.2 拦截器的实现原理 1.3 Struts的执行流程 1.4 拦截器入门 1.4.1 环境搭建 1.4.2 编写拦截器 1.4.3 配置拦截 ...

  5. urlib库

    urllib库是python中最基本的网络请求库,可以模拟浏览器的行为,向指定的服务器发送请求,并可以保存服务器返回的数据. urlopen() urllib.request模块提供了最基本的构造ht ...

  6. navicat for mysql 链接时报错:1251-Client does not support authentication protocol requested by server

    客户端使用navicat for mysql.本地安装了mysql 8.0.但是在链接的时候提示: 主要原因是mysql服务器要求的认证插件版本与客户端不一致造成的. 打开mysql命令行输入如下命令 ...

  7. Ubuntu 用户权限相关命令

    目标 用户 和 权限 的基本概念 用户管理 终端命令 组管理 终端命令 修改权限 终端命令 01. 用户 和 权限 的基本概念 1.1 基本概念 用户 是 Linux 系统工作中重要的一环,用户管理包 ...

  8. uwsgi配置文件示例

    uwsgi配置文件参考 相关路径请根据自己项目的实际路径配置 在进行Nginx+uwsgi部署Django项目的时候,需要Nginx的配置中包含uwsgi的配置项,具体请查看另一篇:Nginx配置文件 ...

  9. CentOS7清理老旧内核

    CentOS7如果是一步步内核升级上来的将会面临一个问题(一般安装了图形化界面的系统常见),由于内核增多/boot/的容量减少,导致启动变慢.这时就需要清理老旧内核,释放/boot/空间. 使用una ...

  10. 【独家】K8S漏洞报告 | CVE-2019-1002101解读

    kubectl cp漏洞CVE-2019-1002101分析 Kube-proxy IPVS添加flag ipvs-strict-arp 近期bug fix数据分析 ——本期更新内容 kubectl ...