1. 程式人生 > >洛谷P3478 [POI2008]STA-Station 題解

洛谷P3478 [POI2008]STA-Station 題解

本題的資料是 n <= 1000000 , 應該是O(n) 演算法;

先考慮最樸素的演算法 , 進行n 次的dfs 求出深度和  , 複雜度是O(n ^2);

如果我們能在第一次dfs的基礎上在對其他點的進行O(1)的求解那就滿足複雜度的要求了;

然後我們畫一下圖(我不太會畫圖就不畫了);

假設我們已經知道了 以x為根的答案 , 然後求出它的子節點y的答案;

然後我們將根往y 移動 , 發現 原先以x為根的子樹中 , 除去以y為根的子樹 , 他們的深度都會加一 , 而 原先y的子樹的所有節點都會減去1 

所以答案asn_y = ans_x + size_x  - size_y; (如下圖)

                 這裡附上我的程式碼

#include<cstdio>
#include<queue>
#include<map>
#include<cstring>
#include<cstdlib>
#include<deque>
#include<iostream>
#include<vector>
#include<algorithm>
#define inf 0x3f3f3f3f
#define
M 1000010 using namespace std; int cnt , head[M] , next[M << 1] , u[M << 1] , n , ans, size[M]; long long d[M] , f[M] , maxn ; void add(int x , int y){ u[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } inline void dfs1(int x , int fa , int dep){ int y ; for (int i = head[x] ; i ; i = next[i]){ y
= u[i]; if ( y == fa) continue; dfs1(y , x , dep + 1); size[x] += size[y] , d[x] += d[y]; } size[x] += 1 , d[x] += dep; } inline void dfs2(int x , int fa){ int y; for (int i = head[x] ; i ; i = next[i]){ y = u[i]; if (y == fa) continue; f[y] = f[x] + n - size[y] * 2; dfs2(y , x); } } int main(){ // freopen("A.out" , "w" , stdout); // freopen("c1.in" , "r" , stdin); scanf("%d" , &n); for (int i = 1 ; i < n ; ++i){ int a , b; scanf("%d%d" , &a , &b); add(a , b); add(b , a); } dfs1(1 , 0 , 0); f[1] = d[1]; dfs2(1 , 0 ); for (int i = 1 ; i <= n ; ++i) if (f[i] > maxn) ans = i , maxn = f[i]; printf ("%d" , ans); return 0; }

注意要把存深度的陣列開longlong