首页 > 其他分享 >P3174 [HAOI2009] 毛毛虫

P3174 [HAOI2009] 毛毛虫

时间:2022-09-28 11:11:53浏览次数:77  
标签:dfs int P3174 pos ec ret 毛毛虫 HAOI2009

简要题意

给你一个 \(n\) 个节点 \(m\) 条边的树,定义“毛毛虫”为树中一条链和链上所有顶点所相连的边所组成的子树。求该树中点数最大的毛毛虫,输出点数。

比如,下面左边的树 \(1\) 中点数最大的毛毛虫就是右边的毛毛虫 \(2\)。

image

\(1 \leq m \lt n \leq 300000\)

思路

一道没有看题解切掉的题。

下面我们称毛毛虫中的最长链为毛毛虫的“躯干”,将躯干上的点连向的非躯干的点的边称为“触手”。

如果我们将躯干上一个点的贡献看成点权的话,那么这就是一个求树上最长链的问题。

问题来了,如何求触手个数?答案就是,触手个数其实就是节点的度减去 \(2\)。

每个点的贡献需要加上自己,也就是说,每个点的贡献就是节点的度 减去 \(1\)。

但是首尾就会多减去 \(1\),没事,最后加上 \(2\) 即可。但这又造成了问题,如果 \(n = 1\) 答案就是 \(0+2=2\),事实上是 \(1\)(因为首尾相同,多加了),这里直接特判 \(n=1\) 即可。

求树上最长链使用两遍 DFS 大法。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 600005;

struct edge{
	int nxt,to;
} g[N];
int head[N],ec;
void add(int u,int v){
	g[++ec].nxt=head[u];
	g[ec].to=v;
	head[u]=ec;
}
int n,m,w[N];

int ret,pos;
void dfs(int u,int fa,int sum){
	if(sum>ret){
		ret=sum;
		pos=u;
	}
	for(int i=head[u];i;i=g[i].nxt){
		int v=g[i].to;
		if(v==fa){
			continue;
		}
		dfs(v,u,sum+w[v]);
	}
}

signed main(){
	cin>>n>>m;
	if(n==1){
	    cout<<1;return 0;
	}
	memset(w,-1,sizeof(w));
	for(int i=1,x,y;i<=m;i++){
		cin>>x>>y;
		add(x,y);add(y,x);
		w[x]++;
		w[y]++;
	}
	dfs(1,0,w[1]);
	ret=0;
	dfs(pos,0,w[pos]);
	ret+=2;
	cout<<ret;
	return 0;
}

AC Record

标签:dfs,int,P3174,pos,ec,ret,毛毛虫,HAOI2009
From: https://www.cnblogs.com/zheyuanxie/p/p3174.html

相关文章