1. 程式人生 > >省選專練之 [HAOI2009]毛毛蟲

省選專練之 [HAOI2009]毛毛蟲

題目描述

對於一棵樹,我們可以將某條鏈和與該鏈相連的邊抽出來,看上去就象成一個毛毛蟲,點數越多,毛毛蟲就越大。例如下圖左邊的樹(圖 1 )抽出一部分就變成了右邊的一個毛毛蟲了(圖 2 )。

輸入輸出格式

輸入格式:

 

在文字檔案 worm.in 中第一行兩個整數 N , M ,分別表示樹中結點個數和樹的邊數。

接下來 M 行,每行兩個整數 a, b 表示點 a 和點 b 有邊連線( a, b ≤ N )。你可以假定沒有一對相同的 (a, b) 會出現一次以上。

 

輸出格式:

 

在文字檔案 worm.out 中寫入一個整數 , 表示最大的毛毛蟲的大小。

簡單樹形DP。

實際本質:樹的最長鏈

點權就是枝葉長度

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
const int N=3e5+100;
int ans=0;
int root;
int Du[N];
int val[N];
struct Front_star{
	int u,v,nxt;
}e[N<<2];
int first[N];
int cnt=0;
void add(int u,int v){
	Du[u]++;
	++cnt;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].nxt=first[u];
	first[u]=cnt;
}
int n,m;
int F[N];
void DFS(int u,int fat){
	if(Du[u]==1){
		F[u]=1;	
		return;
	}
	int now=0;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fat)continue;
		DFS(v,u);
		now=max(now,F[v]);
	}
	F[u]=now+val[u];
}
void DP(int u,int fat){
	int Fx=0,Sx=0;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fat)continue;
		DP(v,u);
		if(Sx<=F[v]){
			Sx=F[v];
			if(Sx>Fx)swap(Sx,Fx);
		}
	}
	ans=max(ans,Sx+Fx+val[u]);
}
int main(){
	read(n);
	read(m);
	for(int i=1;i<=m;++i){
		int u,v;
		read(u);
		read(v);
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n;++i){
		if(Du[i]!=1){
			root=i;
			break;
		}
	}
	for(int i=1;i<=n;++i){
		if(Du[i]==1||Du[i]==2)val[i]=1;
		else val[i]=Du[i]-1;
	}
	DFS(root,0);
	DP(root,0);
	cout<<ans;
}