uoj#339. 【清华集训2017】小 Y 和二叉树(构造)

本文深入探讨了图论中的DFS算法应用,特别是在寻找最优路径和确定根节点方面。通过构造特定序列,采用贪心策略,实现了高效遍历并找到了最小编号节点。此方法对于解决复杂图论问题提供了新的视角。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

膜拜大米饼巨巨

构造思路太神仙了……

先考虑这个序列的开头,肯定是一个度数小于等于\(2\)且标号最小的节点,设为\(u\)

如果一个点度数小于等于\(2\),我们称这个点可以被选择,一个点的\(mn\)为它的子树中(不包括子树的根)能被选择的点中最小的标号

那么如果能够确定根节点,只要从根节点往下\(dfs\),然后每次贪心的选择\(mn\)小的那个节点就好了

为了找到根节点,我们从\(u\)开始往下\(dfs\),先预处理出以\(u\)为根时所有节点的\(mn\),那么每一次往下走的时候,只要判断一下走了之后会不会使中序遍历变得更劣,如果不会的话往下走,否则就停在这里,这个就是根节点了

然后从根节点贪心\(dfs\)一遍就可以得出答案了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=1e6+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int mn[N],ls[N],rs[N],ch[N][2],deg[N];
int n,st,rt,u,v;
void dfs1(int u,int fa){
    int cnt=0;
    go(u)if(v!=fa){
        ch[u][cnt++]=v,dfs1(v,u);
        cmin(mn[u],mn[v]);
    }
}
void dfs2(int u){
    if(!ch[u][0])return rt=u,void();
    if(!ch[u][1]){
        if(ch[u][0]<mn[ch[u][0]])dfs2(ch[u][0]);
        else return rt=u,void();
    }else dfs2(mn[ch[u][0]]<mn[ch[u][1]]?ch[u][1]:ch[u][0]);
}
int dfs3(int u,int fa){
    if(deg[u]==1&&u!=rt)return u;
    int res=n+1,now;if(u==rt&&deg[u]==1||u!=rt&&deg[u]==2)res=u;
    go(u)if(v!=fa){
        now=dfs3(v,u);
        if(now<res)rs[u]=ls[u],ls[u]=v,res=now;
        else rs[u]=v;
    }return res;
}
void dfs4(int u){
    if(ls[u])dfs4(ls[u]);
    print(u);
    if(rs[u])dfs4(rs[u]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),st=n+1;
    fp(i,1,n){
        deg[i]=read(),mn[i]=n+1;
        fp(j,1,deg[i])u=read(),add(i,u);
        if(deg[i]<=2)mn[i]=i,cmin(st,i);
    }
    dfs1(st,0),dfs2(st),dfs3(rt,0),dfs4(rt);
//  fp(i,1,n)printf("%d %d %d\n",i,ls[i],rs[i]);
    return Ot(),0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10273322.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值