給出一個\(N\)個點的樹,找出一個點來,以這個點爲根的樹時,全部點的深度之和最大spa
看到樹,還讓求最大,這種可能不是貪心就是樹形\(DP\),貪心的話樹的形狀無法判斷,果斷放棄,那麼就只能是\(DP\)了。
既然它讓求深度之和,那麼我就直接定義以\(i\)爲根時深度和爲\(DP_i\),接下來就是怎麼轉移的問題了。若是我枚舉每一個點來考慮,那麼還要計算它下邊的子樹和它上邊的子樹,顯然是很差弄,時間複雜度可能在\(O(N^2)\)左右,雖然時間十秒但也不夠用啊,因爲\(n\)大到了1000000,因此這個題仍是得用\(O(n)\)的效率,若是我以某種手段獲得了\(DP_1\),那麼接下來的轉移就好說了,每次往下找一個兒子\(v\),深度減少了\(siz_v\),增長了\(n-siz_v\),這樣就能用兩個\(O(n)\)來完成這個題,最後在\(O(n)\)的統計一下答案就好。code
#include<cstdio> using namespace std; const int N=1e6+10; struct Edge{ int to,nxt; }e[N<<1]; int dep[N],Head[N],len; void Ins(int a,int b){ e[++len].to=b;e[len].nxt=Head[a];Head[a]=len; } int dp[N],siz[N]; void dfs(int u,int fa){ siz[u]=1;dp[u]=dep[u]; for(int i=Head[u];i;i=e[i].nxt){ int v=e[i].nxt; if(v==fa)continue; dep[v]=dep[u]+1; dfs(v,u); siz[u]+=siz[v]; dp[u]+=dp[v]; } } int n; void calc(int u,int fa){ for(int i=Head[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; dp[v]=dp[u]-siz[v]+n-siz[v]; calc(v,u); } } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int a,b; scanf("%d%d",&a,&b); Ins(a,b);Ins(b,a); } dfs(1,0); calc(1,0); int ans=0; for(int i=1;i<=n;i++) if(dp[ans]<dp[i])ans=i; printf("%d\n",ans); }
轉移方程題目問什麼設什麼先,求不出來再考慮換或者輔助一下\(DP\).io