UOJ#339. 【清华集训2017】小 Y 和二叉树 贪心
原文链接 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 和二叉树 贪心的更多相关文章
- [清华集训2017]小 Y 和地铁(神奇思路,搜索,剪枝,树状数组)
世界上最不缺的就是好题. 首先考虑暴搜.(还有什么题是从这东西推到正解的……) 首先单独一个换乘站明显没用,只用考虑一对对的换乘站. 那么有八种情况:(从题解偷图) 然后大力枚举每个换 ...
- 【清华集训】小Y和地铁
图已挂,前往luogu 题目: 小 $\rm Y$ 是一个爱好旅行的 $\rm OIer$.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁.她发现每条地铁线路可以看成平面上的一条 ...
- 清华集训2017D2T1 小 Y 和地铁(metro)
题目:https://www.luogu.org/problem/show?pid=P4005 题意:一条线段,给定n个点(n<=44)其中每个点可能对应另外一个点.如果一个点有对应点,那么就要 ...
- 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)
[UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...
- Loj #2324. 「清华集训 2017」小 Y 和二叉树
Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...
- loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主
#2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较 题目描述 "A fight? Co ...
- [LOJ#2324]「清华集训 2017」小Y和二叉树
[LOJ#2324]「清华集训 2017」小Y和二叉树 试题描述 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙 ...
- [LOJ#2323]「清华集训 2017」小Y和地铁
[LOJ#2323]「清华集训 2017」小Y和地铁 试题描述 小Y是一个爱好旅行的OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的 ...
- 【luoguP4006 清华集训2017】小Y和二叉树
题目描述 小 Y 是一个心灵手巧的 OIer,她有许多二叉树模型. 小 Y 的二叉树模型中,每个结点都具有一个编号,小 Y 把她最喜欢的一个二叉树模型挂在了墙上,树根在最上面,左右子树分别在树根的左下 ...
随机推荐
- 用不上索引的sql
1.使用不等于操作符(<>, !=) 大于可以.小于可以,between and 也可以 2.使用 is null 或 is not null 任何包含null值的列都将不会被包含在索引中 ...
- 获取新技能 ----dispaly: tabel
刚才在总结自适应布局的时候,灵光一现,好像记得哪位大佬提过 display: tabel 这个布局,然后就去查了一下资料,进行了学习,现在简单总结一下. 说白了就是可以给HTML元素指定与表格相关的d ...
- springmvc集成cxf的方法
最近需要在项目中增加webservice接口,供三方调用,下面就把集成的方法展示如下,供大家参考: 第一步:服务端的发布; 1:配置web.xml文件,添加cxf的servlet <servle ...
- android 更新版本
1.UpdateManager package com.rfid.util; import java.io.File; import java.io.FileOutputStream; import ...
- python下调用c语言代码
1)首先,创建一个.c文件,其大体内容如下: 2 #include <Python.h> 99 char * extract(char * path) ...
- xadmin安装
1 安装满足django2的版本 pip3 install https://codeload.github.com/sshwsfc/xadmin/zip/django2 2 urls.py里面增加路由 ...
- Python学习日记(十) 生成器和迭代器
使用dir()我们可以知道这个数据类型的内置函数有什么方法: print(dir(int)) print(dir(bool)) print(dir([])) print(dir({})) print( ...
- 微信小程序 时间戳 转化为 日期格式
util.js : function transTime(unixtime) { var dateTime = new Date(parseInt(unixtime) * 1000) var yea ...
- Android笔记(七十三) Android权限问题整理 非常全面
Android权限系统非常庞大,我们在Android系统中做任何操作都需要首先获取Android系统权限,本文记录了所有的Android权限问题,整理一下分享给大家. 访问登记属性 android.p ...
- 学习python的日常3
python的一些高级特性: 切片(跟名字一样,把一个完整的东西选取一部分自己想要的去切下来):通过切片可以快速的去除一些元素,只要确定好索引位置,避免的循环导致的多写代码 数组,元组,字符串都可以用 ...