传送门:http://codeforces.com/contest/1092/problem/F

F. Tree with Maximum Cost

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given a tree consisting exactly of nn vertices. Tree is a connected undirected graph with n−1n−1 edges. Each vertex vv of this tree has a value avav assigned to it.

Let dist(x,y)dist(x,y) be the distance between the vertices xx and yy. The distance between the vertices is the number of edges on the simple path between them.

Let's define the cost of the tree as the following value: firstly, let's fix some vertex of the tree. Let it be vv. Then the cost of the tree is ∑i=1ndist(i,v)⋅ai∑i=1ndist(i,v)⋅ai.

Your task is to calculate the maximum possible cost of the tree if you can choose vv arbitrarily.

Input

The first line contains one integer nn, the number of vertices in the tree (1≤n≤2⋅1051≤n≤2⋅105).

The second line of the input contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤2⋅1051≤ai≤2⋅105), where aiai is the value of the vertex ii.

Each of the next n−1n−1 lines describes an edge of the tree. Edge ii is denoted by two integers uiui and vivi, the labels of vertices it connects (1≤ui,vi≤n1≤ui,vi≤n, ui≠viui≠vi).

It is guaranteed that the given edges form a tree.

Output

Print one integer — the maximum possible cost of the tree if you can choose any vertex as vv.

Examples
input

Copy
  1. 8
  2. 9 4 1 7 10 1 6 5
  3. 1 2
  4. 2 3
  5. 1 4
  6. 1 5
  7. 5 6
  8. 5 7
  9. 5 8
output

Copy
  1. 121
input

Copy
  1. 1
  2. 1337
output

Copy
  1. 0
Note

Picture corresponding to the first example:

You can choose the vertex 33 as a root, then the answer will be 2⋅9+1⋅4+0⋅1+3⋅7+3⋅10+4⋅1+4⋅6+4⋅5=18+4+0+21+30+4+24+20=1212⋅9+1⋅4+0⋅1+3⋅7+3⋅10+4⋅1+4⋅6+4⋅5=18+4+0+21+30+4+24+20=121.

In the second example tree consists only of one vertex so the answer is always 00.

题意概括:

给出一棵 有 N 个结点 N-1 条边的树,每个结点的权值为 a[ i ], 每条边的边权为 1 .

每一点的贡献 = 该点的深度 * 该点的权值。

所以以不同的点作为 整棵树的根 会得到不同的树结点的贡献总和。

求最大的树结点的贡献组合。

解题思路:

一、树的换根 两次DFS

跑第一次DFS,处理出 Sum[ u ] 以 u 为根的子树的贡献总和(包括 u 结点本身),处理出以 结点1为根 的树的贡献总和 res;

第二次 DFS 换根:

假设 fa = 1, u = 5(即从根为1 转换为根为 5)

由上图可以发现 红色部分的每一个结点都会与 根:u 多连了一条边 ,即红色部分的贡献要加倍(相当于深度+1,所有红色部分结点贡献)。

而红色部分就是 以 u 为根的子树之外的结点:即 ( Sum[ fa ] - Sum[ u ] );

蓝色部分的所有结点 都会与 根 u 少连一条边,即深度-1,蓝色部分结点贡献和减半;

以 fa = 1 为根时,总贡献和为 res;

转换为以 u = 5 为根时,总贡献和为 res + ( Sum[ fa ] - Sum[ u ]) - Sum[ u ];

当 u = 5 为根之后,

Sum[ fa ] = Sum[ fa ] - Sum[ u ] (即红色部分)因为树根变了,所以原本父亲的子树不再是整棵树,而是原来 以 u 为根的子树之外的结点。

Sum[ u ] = res; u 成为整棵树的根,整棵树都是 u 的子树。

按照这种方式递归搜索更新,取最大的res;

递归返回后,还原 Sum[ fa ], Sum[ u ], res 再搜索下一个儿子结点;

AC code:

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #define FOR(x, maxx) for(x = 1; x <= maxx; x++)
  5. #define ZERO(aa, x) memset(aa, x, sizeof(aa))
  6. #define INF 0x3f3f3f3f
  7. #define LL long long
  8. using namespace std;
  9.  
  10. const int MAXN = 2e5+;
  11.  
  12. struct EDGE
  13. {
  14. int v, nxt;
  15. }edge[MAXN<<];
  16. int head[MAXN];
  17. LL sum[MAXN], sumk[MAXN];
  18.  
  19. int cost[MAXN], dep[MAXN];
  20. int N, cnt;
  21. LL ans, res;
  22.  
  23. void add(int from, int to)
  24. {
  25. edge[cnt].v = to;
  26. edge[cnt].nxt = head[from];
  27. head[from] = cnt++;
  28. }
  29. void init()
  30. {
  31. memset(head, -, sizeof(head));
  32. cnt = ;
  33. ans = ;
  34. }
  35.  
  36. void dfs1(int now, int dh, int fa)
  37. {
  38. //puts("zjy");ans = max(res, ans);
  39. int to;
  40. sum[now] = cost[now];
  41. res += 1LL*cost[now]*dh;
  42. // dep[now] = dh;
  43. // f[now] = fa;
  44. //printf("now: %d\n", now);
  45. for(int i = head[now]; i != -; i = edge[i].nxt){
  46. to = edge[i].v;
  47. if(to != fa){
  48. dfs1(to, dh+, now);
  49. sum[now]+=sum[to];
  50. }
  51. }
  52. }
  53.  
  54. void dfs2(int now, int fa)
  55. {
  56. ans = max(res, ans);
  57. int to;
  58. LL a, b, c;
  59. for(int i = head[now]; i != -; i = edge[i].nxt){
  60. to = edge[i].v;
  61. if(to == fa) continue;
  62. a = sum[now], b = sum[to], c = res;
  63. res-=sum[to]; //当前子树的节点距离-1
  64. res+=sum[now]-sum[to]; //当前非子树节点距离+1
  65. sum[now]-=sum[to];
  66. sum[to] = a;
  67. dfs2(to, now);
  68. sum[now] = a; //还原
  69. sum[to] = b;
  70. res = c;
  71. }
  72. }
  73.  
  74. int main()
  75. {
  76. int i, j;
  77. init();
  78. scanf("%I64d", &N);
  79. FOR(i, N) scanf("%I64d", &cost[i]);
  80. int u, v;
  81. for(i = ; i < N; i++){
  82. scanf("%d %d", &u, &v);
  83. add(u, v);
  84. add(v, u);
  85. }
  86. //puts("zjy");
  87. dfs1(, , ); //第一次递归求初始值
  88. dfs2(, );
  89. printf("%I64d\n", ans);
  90. return ;
  91. }

二、树形dp

同样需要一次DFS 预处理出 s[ u ] 以 u 为根的子树的贡献总和(包括 u 结点本身);

状态:dp[ u ]  以 u 为根时,整棵树的贡献和

状态转移:dp[u] = dp[fa] + sum - 2*s[u]; ( sum 为所有结点的权值总和)

假设 fa = 1,u = 5;

dp[ 5 ] = dp[ 1 ] + 红色 - 蓝色 - cost[ u ];

dp[ 5 ] = dp[ 1 ] + ( sum - s[ 5 ]) - s[ 5 ];

dp[ 5 ] = dp[ 1 ]  + sum - 2*s[ 5 ];

AC code:

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #define FOR(x, maxx) for(x = 1; x <= maxx; x++)
  5. #define ZERO(aa, x) memset(aa, x, sizeof(aa))
  6. #define INF 0x3f3f3f3f
  7. #define LL long long
  8. using namespace std;
  9.  
  10. const int MAXN = 2e5+;
  11.  
  12. struct EDGE
  13. {
  14. int v, nxt;
  15. }edge[MAXN<<];
  16. int head[MAXN], cnt;;
  17. LL sum[MAXN], dp[MAXN];
  18. LL cost[MAXN];
  19. LL ans, res;
  20. LL SSum;
  21. int N;
  22.  
  23. void add(int from, int to)
  24. {
  25. edge[cnt].v = to;
  26. edge[cnt].nxt = head[from];
  27. head[from] = cnt++;
  28. }
  29. void init()
  30. {
  31. memset(head, -, sizeof(head));
  32. memset(dp, , sizeof(dp));
  33. SSum = 0LL;
  34. cnt = ;
  35. ans = ;
  36. }
  37.  
  38. void dfs(int now, int fa)
  39. {
  40. int to;
  41. sum[now] = cost[now];
  42. for(int i = head[now]; i != -; i = edge[i].nxt){
  43. to = edge[i].v;
  44. if(to == fa) continue;
  45. dfs(to, now);
  46. sum[now]+=sum[to];
  47. dp[now] = dp[now] + dp[to] + sum[to];
  48. }
  49. }
  50.  
  51. void solve(int now, int fa)
  52. {
  53. int to;
  54. if(fa) dp[now] = dp[fa]+SSum-*sum[now];
  55. for(int i = head[now]; i != -; i = edge[i].nxt){
  56. to = edge[i].v;
  57. if(to == fa) continue;
  58. solve(to, now);
  59. }
  60. ans = max(ans, dp[now]);
  61. }
  62.  
  63. int main()
  64. {
  65. init();
  66. scanf("%d", &N);
  67. for(int i = ; i <= N; i++){
  68. scanf("%I64d", &cost[i]);
  69. SSum+=cost[i];
  70. }
  71. int u, v;
  72. for(int i = ; i < N; i++){
  73. scanf("%d %d", &u, &v);
  74. add(u, v);
  75. add(v, u);
  76. }
  77. //puts("zjy");
  78. dfs(, ); //第一次递归求初始值
  79. solve(, );
  80. printf("%I64d\n", ans);
  81. return ;
  82. }

Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】的更多相关文章

  1. Codeforces Round #527 (Div. 3) . F Tree with Maximum Cost

    题目链接 题意:给你一棵树,让你找一个顶点iii,使得这个点的∑dis(i,j)∗a[j]\sum dis(i,j)*a[j]∑dis(i,j)∗a[j]最大.dis(i,j)dis(i,j)dis( ...

  2. Codeforces Round #499 (Div. 1) F. Tree

    Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...

  3. Codeforces Round #527 (Div. 3)F(DFS,DP)

    #include<bits/stdc++.h>using namespace std;const int N=200005;int n,A[N];long long Mx,tot,S[N] ...

  4. Codeforces Round #135 (Div. 2) D - Choosing Capital for Treeland(两种树形DP)

  5. 2018.12.19 codeforces 1092F. Tree with Maximum Cost(换根dp)

    传送门 sbsbsb树形dpdpdp题. 题意简述:给出一棵边权为1的树,允许选任意一个点vvv为根,求∑i=1ndist(i,v)∗ai\sum_{i=1}^ndist(i,v)*a_i∑i=1n​ ...

  6. Codeforces Round #527 (Div. 3) ABCDEF题解

    Codeforces Round #527 (Div. 3) 题解 题目总链接:https://codeforces.com/contest/1092 A. Uniform String 题意: 输入 ...

  7. Codeforces Round #485 (Div. 2) F. AND Graph

    Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...

  8. Codeforces Round #486 (Div. 3) F. Rain and Umbrellas

    Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/co ...

  9. Codeforces Round #501 (Div. 3) F. Bracket Substring

    题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60 ...

随机推荐

  1. Oracle ORA-27102的解决办法(out of memory)

    原文出自:https://blog.csdn.net/seesun2012 Oracle ORA-27102:out of memory 错误解决办法(简单粗暴,100%能解决内存占用问题) -前置: ...

  2. SpringBoot 开启debug

    项目基于gradle ,今天想断点debug一下springboot,查阅资料后,纪录一下步骤. 创建Remote 创建gradle.properities 在当前项目下创建gradle.proper ...

  3. Vue(五)--组件

    1.组件也需要进行注册才可以使用:分为局部注册和全局注册 <body> <div id="app" > <my-component></m ...

  4. Emmet使用方法

    本文摘自:http://www.iteye.com/news/27580 Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语 ...

  5. Linux 创建python虚拟环境

    使用virtualenv包管理工具来管理虚拟环境 1.安装virtualenv 不知啥原因,第一次安装超时失败,第二次下载到30%超时失败,第三次才安装成功 2.创建虚拟环境 只有python2.7及 ...

  6. Git版本控制工具(1)

    学习Git的最佳资料网站: https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/ 这 ...

  7. 第一行代码 10.2使用HTTP协议访问网络 HttpURLConnection代码中的问题

    实现HttpURLConnection代码的时候,遇到了问题. 怎样点击途中Send Request按钮,没有任何改变. 最后将MainActivity中的一段代码URL url = new URL( ...

  8. Vue中的静态资源管理(src下的assets和static文件夹的区别)

    ### 你可能注意到了我们的静态资源共有两个目录src/assets和static/,你们它们之间有怎样的区别呢? 资源打包 为了回答这个问题,我们需要了解webpack是如何处理静态资源的. 在所有 ...

  9. Python基础-继承与派生

    一.继承 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. python中类的继承分为:单继承和多继承 class P ...

  10. ArcSDE10.2.2使用SQL操作ST_Geometry时报ORA-28579或ORA-20006错误

    ArcSDE10.2.2使用SQL操作ST_Geometry时报ORA-28579或ORA-20006错误 1.测试环境说明 ArcSDE版本:10.2.2 Oracle版本:12.1.0.1和11. ...