题目
题目描述
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 a_va
v
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 \sum\limits_{i = 1}^{n} dist(i, v) \cdot a_i
i=1
∑
n
dist(i,v)⋅a
i
.
Your task is to calculate the maximum possible cost of the tree if you can choose vv arbitrarily.
输入格式
The first line contains one integer nn , the number of vertices in the tree ( 1 \le n \le 2 \cdot 10^51≤n≤2⋅10
5
).
The second line of the input contains nn integers a_1, a_2, \dots, a_na
1
,a
2
,…,a
n
( 1 \le a_i \le 2 \cdot 10^51≤a
i
≤2⋅10
5
), where a_ia
i
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 u_iu
i
and v_iv
i
, the labels of vertices it connects ( 1 \le u_i, v_i \le n1≤u
i
,v
i
≤n , u_i \ne v_iu
i
=v
i
).
It is guaranteed that the given edges form a tree.
输出格式
Print one integer — the maximum possible cost of the tree if you can choose any vertex as vv .
题意翻译
有一n个节点的树,每个节点有一点权ai。
定义dist(x,y)为x到y的边数。
选取一点v,使\sum_{i=1}^{n}dist(i,v)*ai\qquad∑
i=1
n
dist(i,v)∗ai最大
第一行输入n;
第二行输入n个数ai;
接下来n-1行,每行两个数x,y表示x到y有一条边。
输出最大值。
输入输出样例
输入 #1复制
8
9 4 1 7 10 1 6 5
1 2
2 3
1 4
1 5
5 6
5 7
5 8
输出 #1复制
121
输入 #2复制
1
1337
输出 #2复制
0
说明/提示
Picture corresponding to the first example:
You can choose the vertex 33 as a root, then the answer will be 2 \cdot 9 + 1 \cdot 4 + 0 \cdot 1 + 3 \cdot 7 + 3 \cdot 10 + 4 \cdot 1 + 4 \cdot 6 + 4 \cdot 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 .
思路
1.第一次扫描时,任选一个点为根,再“有根树”上执行一次树形DP,也就是回溯时发生的 自底向上的状态转移
2.第二次扫描时,从刚才任选的根出发,对整棵树执行一次深度优先遍历,在,每次递归钱进行自顶向下的推导,计算出换根后的新解
套路比较明显
来看这道题 要求我们选择一个点 使得其他点的深度乘权值之和最大
我们先以一号点为根然后进行预处理 求出来子树的权值和 以及1号节点为根的DP值
考虑第二次扫描
当我们枚举到u-v这条边时 图被分成两部分 画图很显然可得 u节点所在的部分深度都+1 v节点所在深度都-1
所以DP方程呼之欲出:
f[v]=f[u]+sum-size[v]-size[v]
O(n)DFS即可
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+77;
int n,head[N],cnt;
ll siz[N],sum,f[N],ans=0,a[N],dep[N];
struct edge
{
int nxt,to;
}e[N<<1];
void add(int x,int y){
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs1(int x,int fa){
siz[x]=a[x];
for(int i=head[x]; i; i=e[i].nxt){
int v=e[i].to;
if(v==fa) continue;
dep[v]=dep[x]+1;
f[1]=f[1]+(ll)(a[v]*dep[v]);
dfs1(v,x);
siz[x]+=siz[v];
}
}
void dfs2(int x,int fa){
for(int i=head[x]; i; i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
f[y]=f[x]+sum-siz[y]-siz[y];
dfs2(y,x);
}
}
int main()
{
n=read();
for(int i=1; i<=n; i++)
{
a[i]=read();
sum+=a[i];
}
for(int i=1; i<n; i++)
{
int u,v;
u=read(),v=read();
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1; i<=n; i++)
{
ans=max(f[i],ans);
}
printf("%lld",ans);
}