1. 程式人生 > >[POI2008]Sta

[POI2008]Sta

樹形 head dfs AR node IV 所有 mat ext

[POI2008]Sta

Description

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

Input

給出一個數字N,代表有N個點.N<=1000000 下面N-1條邊.

Output

輸出你所找到的點,如果具有多個解,請輸出編號最小的那個.

Sample Input

8
1 4
5 6
4 5
6 7
6 8
2 4
3 4

Sample Output

7

這道題看完題面和數據範圍應該很明顯的是樹形dp了。
\(F[i]\)表示當\(i\)的子樹(1為根節點時i的子樹)的深度和。(\(i\)節點深度視為\(0\)
考慮如何換根轉移,由我們狀態的定義可得
\[dp[v]=dp[k]-(f[v]+size[v])+n-size[v]+f[v]\]


\(dp[k]-(f[v]+size[v])\)即表示當\(k\)為根時,除v以外的子樹的深度和。
加上\(n-size[v]\)是因為當前我們以\(v\)作為根節點,其他節點的深度相對於\(k\)時會\(+1\)
\(f[v]\)\(v\)的子樹對\(v\)的貢獻。
註意long long

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define lll long long
using namespace std;
lll read()
{
    lll x=0
,w=1;char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*w; } lll n,cnt; lll head[1000010]; lll dp[1000010],f[1000010],size[1000010]; struct
node{ lll to,next; }edge[2000010]; void add(lll x,lll y) { cnt++; edge[cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; } void dfs(lll k,lll fa,lll depth) { lll v; for(lll i=head[k];i;i=edge[i].next) { v=edge[i].to; if(v==fa) continue; dfs(v,k,depth+1); f[k]+=f[v]+size[v]; size[k]+=size[v]; } size[k]++; } void DP(lll k,lll fa) { lll v; for(lll i=head[k];i;i=edge[i].next) { v=edge[i].to; if(v==fa) continue; dp[v]=dp[k]-(f[v]+size[v])+n-size[v]+f[v]; DP(v,k); } } int main() { lll x,y,pos,ans=0; n=read(); for(lll i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); } dfs(1,0,0); dp[1]=f[1]; DP(1,0); for(lll i=1;i<=n;i++) { if(dp[i]>ans) { ans=dp[i]; pos=i; } } cout<<pos; }

[POI2008]Sta