<span>【题解】P7807 「DCOI2021」C 魔力滋生</span>

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

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

\(n\) 个点的树,每个点的度不超过 \(2\),也就是说这是一条

首先考虑 \(x=0\):显然此时给出的树 \(T'\) 即原来的树 \(T\),直接读入什么就输出什么即可。

其次考虑 \(x=1\):此时每个点连接了一个新建点,但事实上不难发现,这 \(n\) 个新建点的度均为 \(1\),原来 中的点的度至少为 \(2\)。据此亦不难将所有度为 \(1\) 的点从原来的 上剥离。

满分做法:树的直径

考虑先找到树的最长链。

若满足 \(k=0\),则这条 就对应了最大的 \(n\)

若满足 \(k \ne 0\),则去掉这条 的头部和尾部,因为这两个点一定是新建的(否则 \(k=0\)

去掉之后的链也一定对应了最大的 \(n\)

时间复杂度 \(O(n)\),期望得分 \(100\) 分。

#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');
}

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务