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 把她最喜欢的一个二叉树模型挂在了墙上,树根在最上面,左右子树分别在树根的左下 ...
随机推荐
- Hibernate中Session.get()/load()之区别
原文链接http://sunxin1001.iteye.com/blog/292090 Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象.其区 ...
- python Linux 环境 (版本隔离工具)
python Linux 环境 (版本隔离工具) 首先新建用户,养成良好习惯useradd python 1.安装pyenv GitHub官网:https://github.com/pyenv/pye ...
- 计算机网络原理,TCP&UDP
UDP伪首部:计算校验和时会用到,然后实际传输过程中里包含的IP地址没有什么用. UDP校验和计算:求数值之和,如果溢出回卷,最后求出反码;UDP伪首部,UDP首部,应用层数据相加 tcp报文,最短2 ...
- 快速为不同 Git 平台配置用户
在 ~ 目录下创建 config 文件可以为项目配置默认的用户信息,但如果希望经常切换,那么最好就是通过命令为项目单独设置用户. 我使用的 shell 是 zsh, 所以我在 ~/.zshrc 文件中 ...
- Win10-安装.net 2,3,.3.5
win10x64(ver1809).iso放镜像到光驱后执行cmd(.net3.5包括2和3)dism.exe /online /enable-feature /featurename:NetFx3 ...
- Android笔记(五十一) 短信验证码集成——mob平台
官方网站:www.mob.com 注册帐号,下载SDK,导入SDK就不说了,主要写一下简单集成如何使用,以后忘记了也可以翻着看看. 详细的可以参考官方文档: http://wiki.mob.com/a ...
- Python中的列表推导式
Python里面有个很棒的语法糖(syntactic sugar),它就是 list comprehension ,有人把它翻译成“列表推导式”,也有人翻译成“列表解析式”.名字听上去很难理解,但是看 ...
- mysql简单优化的一些总结
mysql对cpu的利用特点: 5.1之前,多核支持较弱:5.1可利用4个核:5.5可利用24核:5.6可利用64个核:每个连接对应一个线程,每个并发query只能使用一个核 mysql对内存的利用特 ...
- centos7安装redis 并配置在后台启动
官网 https://redis.io/download 先进入 目录 /usr/local 1 下载文件包 $ wget http://download.redis.io/releases/red ...
- java基础(11)---模块(java9)
一.模块介绍 二.模块可以解决的问题 三.module-info.java文件 四.一个项目就可变成一个模块