原文链接 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. 解决cxf+springmvc发布的webservice,缺少types,portType和message标签的问题

    用cxf+spring发布了webservice,发现生成的wsdl的types,message和portType都以import的方式导入的.. 原因:命名空间问题 我想要生成的wsdl在同个文件中 ...

  2. Oracle 创建与管理用户

    标识用户是 Oracle 数据库管理的基本要求之一,每一个能够连接到数据库的用户都必须是系统的合法用户.用户想要使用 Oracle 的系统资源,就必须拥有相应的权限. 一.身份验证 Oracle 为用 ...

  3. FPM-OVP增强实例-银行账户

    本文是基于NWBC银行账户信息进行增强,相关过程如下: 1.定位需要增强的界面 首先登陆SAP-GUI(尽量EN登陆,ZH可能乱码),输入TCODE:NWBC跳转到浏览器界面,新建银行账户: 注意上图 ...

  4. ABAP开发者上云的时候到了 - 现在大家可以免费使用SAP云平台ABAP环境的试用版了

    之前Jerry已经写了一系列SAP Cloud Platform ABAP编程环境的文章,当时使用的环境,是SAP专门为SAP社区导师们创建的. 当时也有朋友留言,询问大家何时才能使用到免费的SAP云 ...

  5. Linux网卡上添加多个IP

    1.查看现有网卡ip addr show看到ens_xxx 2.进入网卡配置项cd /etc/sysconfig/network-scripts/vim ifcfg-ens192末尾添加2行:IPAD ...

  6. vs2017 官方下载地址 和 官方建立脱机安装包的方法

    vs2017 官方下载地址: https://docs.microsoft.com/zh-cn/visualstudio/releasenotes/vs2017-relnotes VS2017 官方建 ...

  7. CentOS 7.x 配置静态 IP 并启用

    centos 7.x 配置静态 IP 并启用 0 问题由来 通过查询本机的IP,发现本机并没有有效IP: [pan@localhost ~]$ ip addr 所以,我们需要设置本机的静态IP,并启用 ...

  8. python3 操作 hive 安装依赖包整理

    安装依赖pip install saslpip install thriftpip install thrift-saslpip install PyHive windows安装sasl报错,解决方案 ...

  9. Spring-02 -Spring 创建对象的三种方式 :1.通过构造方法创建/2.实例工厂/3.静态工厂

    通过构造方法创建  1.1 无参构造创建:默认情况. 1.2 有参构造创建:需要明确配置 1.2.1 需要在类中提供有参构造方法 1.2.2 在 applicationContext.xml 中设置调 ...

  10. LGOJP2831 愤怒的小鸟

    题目链接 题目链接 题解 数据范围显然状压/爆搜. 考虑\(f[S]\)表示二进制下已打了的猪的集合. 可以枚举\(S\)的子集\(S_1\),判定\(S\)中\(S_1\)的补集\(S_2\)是否合 ...