loj2324 「清华集训 2017」小 Y 和二叉树

https://loj.ac/problem/2324

太智障,一开始以为中序遍历的第一个点一定是一个叶子,想了个贪心。然而,手算了一下,第一个点都过不了啊。

input

5
2 3 4
1 3
3 5 1 2
1 1
1 3

output

1 2 3 5 4

如果树的形态确定,那么第一个中序遍历应该是,从根开始一直往左儿子走,直到当前点没有左儿子,那么这个点就是第一个走到的点。

这个点的度一定$<3$。

于是把贪心稍微换了换,一不小心就A了。

我们找到度$<3$的编号最小的点$d$作为中序遍历走到的第一个点。

然后他的度是1或者2。我们知道,根的度也是1或者2。

如果是2,我要选一条作为父边,一个作为右儿子的儿边。

比较哪个作为右儿子更优。如果一个点作为右儿子,那么他这个子树里面,度数$<3$的编号最小的点,编号一定尽量小。

因为那个点会是我们下一个会走到的点。

然后对于已经确定了是右儿子的那个树,我们可以dfs贪心求字典序最小的中序遍历。

那么,我们想一下,我现在确定了父边,我就可以继续往父边走,

如果这个点的度数$=3$,其中一度是左儿子我们走来的地方,剩下两天边,我们用相同方式比较,看哪个作为右儿子更优。

如果当前这个点度数$=1$,我们找到了根。

如果当前这个点度数$=2$,如果当前这个点可以是根也可以不是根。

我们要判断一下他作为根(那条边作为右儿子)更优还是,那条边作为父边更优。

具体比较方式是,我们看这个条边所到达点$x$,是$x$要小一些还是$x$子树里面度数$<3$的编号最小的点的编号小一些。

如果找到了根,那么就对于右子树dfs贪心求字典序最小的中序遍历。

我们做这道题的时候,就用$d$为根建树,然后预处理每个子树度数$<3$的编号最小的点。

我的代码中,dfs1表示还没有找到根,即,我在$d$到根的路径上。dfs2表示确定了一棵子树,我贪心求中序遍历。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=2e6+7,INF=0x3f3f3f3f;
int n,d[maxn],s[maxn],RT;

char cc;ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

int fir[maxn],nxt[maxn],to[maxn],e=0;
void add(int x,int y) {
	to[++e]=y;nxt[e]=fir[x];fir[x]=e;
}

void DFS(int pos,int f) {
	if(d[pos]==3) s[pos]=INF; else s[pos]=pos;
	int y,z;
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f) continue;
		DFS(z,pos);
		s[pos]=min(s[pos],s[z]);
	}
}
#define lc son[0]
#define rc son[1]
int ans[maxn],tot;

void dfs2(int pos,int f) {
	int son[2],p=0,y,z;
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f) continue;
		son[p++]=z;
	}
	if(p==0) {ans[++tot]=pos;return;}
	if(p==1) {
		if(s[lc]<pos) dfs2(lc,pos),ans[++tot]=pos;
		else ans[++tot]=pos,dfs2(lc,pos);
		return;
	}
	if(s[lc]<s[rc]) dfs2(lc,pos); else dfs2(rc,pos);
	ans[++tot]=pos;
	if(s[lc]>s[rc]) dfs2(lc,pos); else dfs2(rc,pos);
}

void dfs1(int pos,int f) {
	int son[2],p=0,y,z; ans[++tot]=pos;
	for(y=fir[pos];y;y=nxt[y]) {
		if((z=to[y])==f) continue;
		son[p++]=z;
	}
	if(p==0) return;
	if(p==1) {//root or not root
		if(lc>s[lc]) dfs2(lc,pos);
		else dfs1(lc,pos);
		return;
	}
	if(s[lc]<s[rc]) dfs2(lc,pos),dfs1(rc,pos);
	else dfs2(rc,pos),dfs1(lc,pos);
}

int main() {
	read(n); int x;
	For(i,1,n) {
		read(d[i]);
		if(d[i]<3&&RT==0) RT=i;
		For(j,1,d[i]) {
			read(x);
			add(i,x);
		}
	}
	DFS(RT,0);
	dfs1(RT,0);
	For(i,1,n) printf("%d ",ans[i]);
	printf("\n");
	return 0;
}

 

posted @ 2018-06-21 18:15  shixinyi  阅读(260)  评论(0编辑  收藏  举报