【题解】「DCOI2021」C 魔力滋生

· · 题解

upd on 2021.10.26:加入代码,删减并修改部分内容。这本身是一篇高赞题解,因此管理员就不用费心再阅读一遍了。

\rm C~\text{魔力滋生}

部分分提示正解:前两个 Subtask 一个满足 x=0 另一个满足 x=1,提示了分类讨论。

首先考虑 $x=0$:显然此时给出的树 $T'$ 即原来的树 $T$,直接读入什么就输出什么即可。 其次考虑 $x=1$:此时每个点连接了一个新建点,但事实上不难发现,这 $n$ 个新建点的度均为 $1$,原来 **链** 中的点的度至少为 $2$。据此亦不难将所有度为 $1$ 的点从原来的 **链** 上剥离。 **满分做法:树的直径** 考虑先找到树的最长链。 若满足 $k=0$,则这条 **链** 就对应了最大的 $n$。 若满足 $k \ne 0$,则去掉这条 **链** 的头部和尾部,因为这两个点一定是新建的(否则 $k=0$) 去掉之后的链也一定对应了最大的 $n$。 时间复杂度 $O(n)$,期望得分 $100$ 分。 ```cpp #include<cstdio> #include<cstring> inline int in(); inline void wr(int); const int N=(int)1e6+5; struct Node{ int next,to; }s[N<<1];int head[N],sLen; inline void AddEdge(int,int); inline void dfs(int); int dep[N],fa[N],q[N]; int main(int argc,char**argv){ #ifndef ONLINE_JUDGE freopen(argv[1],"r",stdin); freopen(argv[2],"w",stdout); #endif register int m=in(),k=in(); for(register int i=1;i<m;++i) AddEdge(in(),in()); dfs(1); register int root=0; for(register int i=1;i<=m;++i) if(dep[i]>dep[root]) root=i; memset(dep,0,sizeof(dep)); memset(fa,0,sizeof(fa)); dfs(root); register int tail=0; for(register int i=1;i<=m;++i) if(dep[i]>dep[tail]) tail=i; if(m==1){ wr(1),putchar('\n'); return 0; } //only one node if(!k){ while(tail!=root){ q[++q[0]]=tail; tail=fa[tail]; } q[++q[0]]=tail; wr(q[0]),putchar('\n'); for(register int i=1;i<q[0];++i) wr(i),putchar(' '),wr(i+1),putchar('\n'); } else{ tail=fa[tail]; if(root==tail){ wr(1),putchar('\n'); return 0; } while(fa[tail]!=root){ q[++q[0]]=tail; tail=fa[tail]; } q[++q[0]]=tail; wr(q[0]),putchar('\n'); for(register int i=1;i<q[0];++i) wr(i),putchar(' '),wr(i+1),putchar('\n'); } } inline void dfs(int u){ dep[u]=dep[fa[u]]+1; for(register int i=head[u];i;i=s[i].next){ register int v=s[i].to; if(v==fa[u])continue; fa[v]=u,dfs(v); } } inline void AddEdge(int u,int v){ s[++sLen].next=head[u]; s[sLen].to=v;head[u]=sLen; s[++sLen].next=head[v]; s[sLen].to=u;head[v]=sLen; } inline int in(){ register char c=getchar(); register int x=0,f=1; for(;c<'0'||c>'9';c=getchar()) if(c=='-')f=-1; for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c&15); return x*f; } inline void wr(int x){ if(x<0)putchar('-'),x=-x; if(x/10)wr(x/10); putchar(x%10+'0'); } ``` ![](bilibili:BV1U3411z7SQ)