[POI2008]Sta
阿新 • • 發佈:2018-06-19
樹形 head dfs AR node IV 所有 mat ext
\(dp[k]-(f[v]+size[v])\)即表示當\(k\)為根時,除v以外的子樹的深度和。
加上\(n-size[v]\)是因為當前我們以\(v\)作為根節點,其他節點的深度相對於\(k\)時會\(+1\)。
\(f[v]\)即\(v\)的子樹對\(v\)的貢獻。
註意long long
[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