zoukankan      html  css  js  c++  java
  • 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("
    ");
    	return 0;
    }
    
  • 相关阅读:
    常用的长度单位
    HTML常用的列表标签
    html常用文本标签
    CSS选择器及优先级
    块级元素与内联元素
    移动端app打包
    内联框架
    Leetcode303.区域和检索-数组不可变
    Leetcode107.二叉树的层次遍历||
    Leetcode784.字母大小写全排列
  • 原文地址:https://www.cnblogs.com/Serene-shixinyi/p/9210426.html
Copyright © 2011-2022 走看看