1. 程式人生 > >BZOJ1131 [POI2008]Sta 其他

BZOJ1131 [POI2008]Sta 其他

brush algorithm 最大 根節點 cpp sum 深度 同時 line

原文鏈接http://www.cnblogs.com/zhouzhendong/p/8081100.html


題目傳送門 - BZOJ1131


題意概括

  給出一個N個點的樹,找出一個點來,以這個點為根的樹時,所有點的深度之和最大。


題解

  嘻,這題不卡棧。

  假設以1為根

  先跑一遍dfs,算出每一個子樹的節點數size,同時算出以1為根節點的深度和。

  然後再跑一遍dfs,這一回,我們就可以算答案了。

  假設我們要把樹根從一條邊的一個節點移向另一個節點,那麽,這兩個節點為根的答案差就是這條邊兩端的節點個數差。因為其中一個節點代表的子樹上的節點都要多走一步到根,而另一邊少走一步。這樣就可以在O(n)的時間復雜度內solve這一題了。


代碼

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=1000005;
struct Gragh{
	int cnt,y[N*2],nxt[N*2],fst[N];
	void clear(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b){
		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g;
int n,size[N],ans;
LL sum[N],res[N];
void dfs1(int rt,int pre){
	size[rt]=1,sum[rt]=0;
	for (int i=g.fst[rt];i;i=g.nxt[i])
		if (g.y[i]!=pre){
			int s=g.y[i];
			dfs1(s,rt);
			size[rt]+=size[s];
			sum[rt]+=sum[s];
		}
	sum[rt]+=size[rt]-1;
}
void dfs2(int rt,int pre){
	res[rt]=res[pre]-size[rt]+(n-size[rt]);
	if (!ans||res[rt]>res[ans]||(res[rt]==res[ans]&&rt<ans))
		ans=rt;
	for (int i=g.fst[rt];i;i=g.nxt[i])
		if (g.y[i]!=pre)
			dfs2(g.y[i],rt);
}
int main(){
	g.clear();
	scanf("%d",&n);
	for (int i=1,a,b;i<n;i++){
		scanf("%d%d",&a,&b);
		g.add(a,b);
		g.add(b,a);
	}
	dfs1(1,0);
	ans=0;
	res[0]=sum[1]+n;
	dfs2(1,0);
	printf("%d",ans);
	return 0;
}

  

BZOJ1131 [POI2008]Sta 其他