[LOJ2324][树形DP]清华集训2017:小 Y 和二叉树

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/89040043

LOJ2324

题外话:为啥这个小和Y中间有个空格,每次在前缀查询的网站都搜不出来

首先,一个度数=3的点不可能成为叶子节点
最左边的叶子节点就是这棵树的中序遍历的第一位,所以我们可以DP确定这个叶子节点是多少,设 f [ i ] f[i] 表示 i i 点的子树中中序遍历的第一位最小可能是多少
然后确定了最终中序遍历的第一位之后,可以通过这个点向上扩展
具体的,如果这个点只有一个子树,判断一下这个点和子树的 f f 的大小选择放在这个点右儿子还是父亲
如果有两个子树,那就 f f 小的放右儿子, f f 大的放父亲,也要与根节点比较一下,讨论一下即可

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1000010;
int n,m,d[N],rt,st;
int ls[N],rs[N];
int lc[N],rc[N],f[N];
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs1(int v,int fa){
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(y==fa) continue;
		if(!lc[v]) lc[v]=y;else rc[v]=y;
		dfs1(y,v); 
		f[v]=min(f[y],f[v]);
	}
}
void find(int v){
	if(d[v]==1 && v!=st) {rt=v;return;}
	else if(v!=st && d[v]==2 || d[v]==1 && v==st){
		if(lc[v]<f[lc[v]]) find(lc[v]);
		else{rt=v;return;}
	}
	else{
		if(f[lc[v]]>f[rc[v]]) find(lc[v]);
		else find(rc[v]);
	}
}
int dfs2(int v,int fa){
	if(d[v]==1 && v!=rt) return v;
	int tmp=n+1; if(v!=rt && d[v]==2 || v==rt && d[v]==1) tmp=v;
	for(int i=head[v],now;i;i=nxt[i]){
		int y=vis[i];
		if(y==fa) continue;
		if((now=dfs2(y,v))<tmp) rs[v]=ls[v],ls[v]=y,tmp=now;
		else rs[v]=y;
	}
	return tmp;
}
void put(int v){
	if(ls[v]) put(ls[v]);
	cout<<v<<" ";
	if(rs[v]) put(rs[v]);
}
int main(){  
	int size=100<<20;
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size)); 

	n=read();
	for(int i=1;i<=n;i++){
		d[i]=read();
		for(int x,j=1;j<=d[i];j++) x=read(),add(i,x);
		if(d[i]<=2) {f[i]=i; if(!st) st=i;} else f[i]=n+1;
	}
	dfs1(st,0);find(st);dfs2(rt,0);
	put(rt);
	exit(0);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/89040043