• luogu P4006 小 Y 和二叉树


    luogu

    loj

    可以发现度数(< 3)的点可以作为先序遍历的第一个点,那么就把度数(< 3)的编号最小的点作为第一个点.然后现在要确定它的左右儿子(或者是右儿子和父亲).我们把第一个点作为根,设(f_x)(x)子树内先序遍历第一个点的最小值,一遍树型dp求出来

    做的时候要用个变量记录这个点要放左右儿子还是右儿子和父亲,如果当前这个点是上一个点的父亲(或者是第一个点),那么这个点就要放右儿子和父亲,否则放左右儿子

    如果只有一个儿子(y),就比较两种方式哪一种得到的下一个数最小.如果要放左右儿子,那如果(f_y<x)(y)就在左子树,否则在右子树;如果要放右儿子和父亲,然后(f_y<y)就放右儿子,否则放父亲

    如果有两个儿子,就把(f)更小的放在前面,也就是放左右儿子是(f)更小的放左儿子,放右儿子和父亲时(f)更小的放右儿子

    确定好位置后就递归进子树处理子树答案

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=1e6+10;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[N<<1],nt[N<<1],hd[N],tot=1;
    void add(int x,int y)
    {
    	++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    }
    int n,dg[N],f[N];
    void dfs(int x,int ffa)
    {
    	f[x]=n+1;
    	int cn=0;
    	for(int i=hd[x];i;i=nt[i])
    	{
    		int y=to[i];
    		if(y==ffa) continue;
    		dfs(y,x),f[x]=min(f[y],f[x]),++cn;
    	}
    	if(cn<2) f[x]=min(f[x],x);
    }
    void dd(int x,int ffa,bool ty)
    {
    	--dg[x];
    	if(!dg[x])
    	{printf("%d ",x);return;}
    	if(ty==1)
    	{
    		printf("%d ",x);
    		if(dg[x]==1)
    		{
    			int c1=0;
    			for(int i=hd[x];i;i=nt[i])
    			{
    				int y=to[i];
    				if(y!=ffa) c1=y;
    			}
    			dd(c1,x,f[c1]==c1);
    		}
    		else
    		{
    			int c1=0,c2=0;
    			for(int i=hd[x];i;i=nt[i])
    			{
    				int y=to[i];
    				if(y!=ffa) c2=c1,c1=y;
    			}
    			if(f[c1]<f[c2]) dd(c1,x,0),dd(c2,x,1);
    			else dd(c2,x,0),dd(c1,x,1);
    		}
    	}
    	else
    	{
    		if(dg[x]==1)
    		{
    			int c1=0;
    			for(int i=hd[x];i;i=nt[i])
    			{
    				int y=to[i];
    				if(y!=ffa) c1=y;
    			}
    			if(f[c1]<x)
    			{
    				dd(c1,x,0);
    				printf("%d ",x);
    			}
    			else
    			{
    				printf("%d ",x);
    				dd(c1,x,0);
    			}
    		}
    		else
    		{
    			int c1=0,c2=0;
    			for(int i=hd[x];i;i=nt[i])
    			{
    				int y=to[i];
    				if(y!=ffa) c2=c1,c1=y;
    			}
    			if(f[c1]<f[c2])
    			{
    				dd(c1,x,0);
    				printf("%d ",x);
    				dd(c2,x,0);
    			}
    			else
    			{
    				dd(c2,x,0);
    				printf("%d ",x);
    				dd(c1,x,0);
    			}
    		}
    	}
    }
    
    int main()
    {
    	n=rd();
    	for(int i=1;i<=n;++i)
    	{
    		dg[i]=rd();
    		for(int j=1;j<=dg[i];++j) add(i,rd());
    	}
    	int rt=n+1;
    	for(int i=1;i<=n;++i)
    		if(dg[i]<3) {rt=i;break;}
    	dfs(rt,0);
    	++dg[rt],dd(rt,0,1);
        return 0;
    }
    
  • 相关阅读:
    正则表达式练习,持续更新中
    Jquery使用mouseenter和mouseleave实现鼠标经过弹出层且可以点击
    SQL查找 删除重复数据只保留一条
    TreeView(C#)无限目录树代码片段
    ora-01440:要减小精度或标度,则要修改的列必须为空
    SQL查询和删除重复字段的内容
    CodeSmith(C#)简单示例及相关小知识
    MSSQL 自定义函数详解
    一些精妙的sql语句收集
    134.Gas Station
  • 原文地址:https://www.cnblogs.com/smyjr/p/11569626.html
Copyright © 2020-2023  润新知