fork download
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. using ll = long long;
  5.  
  6. int main() {
  7. ios::sync_with_stdio(false);
  8. cin.tie(nullptr);
  9.  
  10. int n;
  11. if(!(cin >> n)) return 0;
  12. vector<ll> w(n+1);
  13. for (int i = 1; i <= n; ++i) cin >> w[i];
  14. vector<vector<int>> g(n+1);
  15. g.reserve(n+1);
  16. for (int i = 0; i < n-1; ++i) {
  17. int u, v; cin >> u >> v;
  18. g[u].push_back(v);
  19. g[v].push_back(u);
  20. }
  21.  
  22. auto bfs_far = [&](int s, vector<int>* parent_out=nullptr)->int{
  23. vector<int> par(n+1, -1);
  24. queue<int> q; q.push(s); par[s]=0;
  25. int last=s;
  26. while(!q.empty()){
  27. int u=q.front(); q.pop();
  28. last=u;
  29. for(int v: g[u]) if(par[v]==-1){
  30. par[v]=u; q.push(v);
  31. }
  32. }
  33. if(parent_out) *parent_out = move(par);
  34. return last;
  35. };
  36.  
  37. vector<int> par1;
  38. int a = bfs_far(1);
  39. int b = bfs_far(a, &par1);
  40.  
  41. // reconstruct a-b path
  42. vector<int> path;
  43. for(int x=b; x!=0; x=par1[x]) path.push_back(x);
  44. // path now from b -> ... -> a ; reverse to a..b
  45. reverse(path.begin(), path.end());
  46. int dlen = (int)path.size()-1; // số cạnh của đường kính
  47.  
  48. // ---- helpers for component DP (không đệ quy) ----
  49. struct CompRes {
  50. int height; // độ sâu lớn nhất từ root đến lá trong component
  51. ll sumBest; // Sum = tổng G dọc đường tốt nhất
  52. ll valBest; // Val = tổng k*G (k bắt đầu từ 1) dọc đường tốt nhất
  53. };
  54.  
  55. auto solve_component = [&](int root, int forbidParent)->CompRes{
  56. // iterative postorder on the component that does NOT cross (root <-> forbidParent)
  57. vector<int> order;
  58. order.reserve(1024);
  59. vector<int> parent(n+1, -2); // -2 = unseen; -1 = no parent (root)
  60. vector<int> stk; stk.reserve(1024);
  61. // stack of (u, iterator index, entered?)
  62. vector<int> itIdx(n+1, 0);
  63.  
  64. // manual stack for postorder
  65. parent[root] = -1;
  66. stk.push_back(root);
  67. vector<int> visited;
  68. visited.reserve(1024);
  69. while(!stk.empty()){
  70. int u = stk.back();
  71. if(itIdx[u] == 0) visited.push_back(u); // first time we see u
  72. if(itIdx[u] < (int)g[u].size()){
  73. int v = g[u][itIdx[u]++];
  74. if(v == parent[u]) continue;
  75. if(u==root && v==forbidParent) continue; // cut the center edge
  76. parent[v] = u;
  77. stk.push_back(v);
  78. }else{
  79. order.push_back(u);
  80. stk.pop_back();
  81. }
  82. }
  83. // compute subsum (=G), height, DP
  84. unordered_set<int> inComp(visited.begin(), visited.end());
  85. // arrays only for nodes in component
  86. // to avoid allocating n-sized arrays each call, use unordered_map-like via vectors + check set
  87. // but for speed and memory, we use arrays of size n+1 reused; mark only used nodes.
  88. static vector<ll> subsum, sumBest, valBest;
  89. static vector<int> height;
  90. if((int)subsum.size()!=n+1){
  91. subsum.assign(n+1,0);
  92. sumBest.assign(n+1,0);
  93. valBest.assign(n+1,0);
  94. height.assign(n+1,0);
  95. }
  96. for(int u: order){
  97. ll s = w[u];
  98. int h = 0;
  99. for(int v: g[u]){
  100. if(v==parent[u]) continue;
  101. s += subsum[v];
  102. h = max(h, height[v]+1);
  103. }
  104. subsum[u] = s; // G(u) trong component
  105. height[u] = h;
  106.  
  107. if(h==0){
  108. sumBest[u] = subsum[u];
  109. valBest[u] = subsum[u]; // k=1
  110. }else{
  111. // chọn child trên nhánh sâu nhất cho giá trị lớn nhất
  112. ll bestValShift = LLONG_MIN;
  113. ll ch_sum = 0, ch_val = 0;
  114. for(int v: g[u]){
  115. if(v==parent[u]) continue;
  116. if(height[v]+1 == h){
  117. ll cand = valBest[v] + sumBest[v];
  118. if(cand > bestValShift){
  119. bestValShift = cand;
  120. ch_sum = sumBest[v];
  121. ch_val = valBest[v];
  122. }
  123. }
  124. }
  125. sumBest[u] = subsum[u] + ch_sum;
  126. valBest[u] = subsum[u] + bestValShift; // 1*G(u) + (val_child + sum_child)
  127. }
  128. }
  129. if(inComp.find(root)==inComp.end()){
  130. // component is empty (shouldn't happen)
  131. return {0, 0, 0};
  132. }
  133. return {height[root], sumBest[root], valBest[root]};
  134. };
  135.  
  136. auto solve_center_vertex = [&](int c)->long long{
  137. // Root whole tree at c to get subsum (=G) and DP for all nodes
  138. // iterative postorder from c
  139. vector<int> parent(n+1, -2), order;
  140. order.reserve(n);
  141. vector<int> stk; stk.reserve(n);
  142. vector<int> itIdx(n+1, 0);
  143. parent[c] = -1;
  144. stk.push_back(c);
  145. while(!stk.empty()){
  146. int u = stk.back();
  147. if(itIdx[u] < (int)g[u].size()){
  148. int v = g[u][itIdx[u]++];
  149. if(v==parent[u]) continue;
  150. parent[v]=u; stk.push_back(v);
  151. }else{
  152. order.push_back(u);
  153. stk.pop_back();
  154. }
  155. }
  156. static vector<ll> subsum, sumBest, valBest;
  157. static vector<int> height;
  158. if((int)subsum.size()!=n+1){
  159. subsum.assign(n+1,0);
  160. sumBest.assign(n+1,0);
  161. valBest.assign(n+1,0);
  162. height.assign(n+1,0);
  163. }
  164. for(int u: order){
  165. ll s = w[u];
  166. int h = 0;
  167. for(int v: g[u]){
  168. if(v==parent[u]) continue;
  169. s += subsum[v];
  170. h = max(h, height[v]+1);
  171. }
  172. subsum[u]=s; height[u]=h;
  173. if(h==0){
  174. sumBest[u]=s; valBest[u]=s;
  175. }else{
  176. ll bestShift = LLONG_MIN, ch_s=0, ch_v=0;
  177. for(int v: g[u]){
  178. if(v==parent[u]) continue;
  179. if(height[v]+1==h){
  180. ll cand = valBest[v] + sumBest[v];
  181. if(cand > bestShift){
  182. bestShift=cand; ch_s=sumBest[v]; ch_v=valBest[v];
  183. }
  184. }
  185. }
  186. sumBest[u]=s + ch_s;
  187. valBest[u]=s + bestShift;
  188. }
  189. }
  190.  
  191. // g_center = tổng trọng số toàn cây
  192. ll g_center = subsum[c];
  193.  
  194. // Thu thập thông tin theo từng nhánh (hàng xóm của c)
  195. struct Item{ int id; int h; ll sumB, valB; };
  196. vector<Item> items;
  197. for(int x: g[c]){
  198. items.push_back({x, height[x], sumBest[x], valBest[x]});
  199. }
  200. // tìm hai độ sâu lớn nhất
  201. int h1=-1, h2=-1;
  202. for(auto &it: items){
  203. if(it.h > h1){ h2=h1; h1=it.h; }
  204. else if(it.h > h2){ h2=it.h; }
  205. }
  206. // các ứng viên cho mỗi phía
  207. vector<Item> A,B;
  208. for(auto &it: items){
  209. if(it.h==h1) A.push_back(it);
  210. if(it.h==h2) B.push_back(it);
  211. }
  212.  
  213. auto pick_max = [](const vector<Item>& vec, bool useValPlusSum, int banId=-1)->Item{
  214. Item best{-1,-1,0,0};
  215. long long bestScore = LLONG_MIN;
  216. for(auto &it: vec){
  217. if(it.id==banId) continue;
  218. long long sc = useValPlusSum ? (it.valB + it.sumB) : it.valB;
  219. if(sc > bestScore){
  220. bestScore = sc; best = it;
  221. }
  222. }
  223. return best;
  224. };
  225.  
  226. ll ans = 0;
  227.  
  228. // hướng 1: đi từ phía có h1 trước rồi qua tâm, rồi tới phía h2
  229. {
  230. Item L = pick_max(A, /*useValPlusSum=*/false);
  231. Item R = pick_max(B, /*useValPlusSum=*/true, (h1==h2?L.id:-1)); // nếu bằng nhau, tránh trùng nhánh
  232. if(L.id!=-1 && R.id!=-1){
  233. ll L1 = h1;
  234. ll S = L.valB + (L1+1)*g_center + (L1+1)*R.sumB + R.valB + R.sumB;
  235. ans = max(ans, S);
  236. }
  237. }
  238. // hướng 2: đảo lại
  239. {
  240. Item R = pick_max(B, /*useValPlusSum=*/false);
  241. Item L = pick_max(A, /*useValPlusSum=*/true, (h1==h2?R.id:-1));
  242. if(L.id!=-1 && R.id!=-1){
  243. ll L2 = h2;
  244. ll S = R.valB + (L2+1)*g_center + (L2+1)*L.sumB + L.valB + L.sumB;
  245. ans = max(ans, S);
  246. }
  247. }
  248. return ans;
  249. };
  250.  
  251. long long answer = 0;
  252. if(dlen % 2 == 0){
  253. // tâm là đỉnh
  254. int c = path[dlen/2];
  255. answer = solve_center_vertex(c);
  256. }else{
  257. // tâm là cạnh (u, v)
  258. int u = path[dlen/2], v = path[dlen/2 + 1];
  259. CompRes A = solve_component(u, v);
  260. CompRes B = solve_component(v, u);
  261. // hai hướng
  262. long long S1 = A.valBest + (ll)A.height * B.sumBest + B.valBest;
  263. long long S2 = B.valBest + (ll)B.height * A.sumBest + A.valBest;
  264. answer = max(S1, S2);
  265. }
  266.  
  267. cout << answer << "\n";
  268. return 0;
  269. }
  270.  
Success #stdin #stdout 0.01s 5320KB
stdin
6
1 2 3 4 5 6
1 2
2 3
2 4
5 6
4 5
stdout
104