Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】
传送门:http://codeforces.com/contest/1092/problem/F
F. Tree with Maximum Cost
2 seconds
256 megabytes
standard input
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.
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.
Print one integer — the maximum possible cost of the tree if you can choose any vertex as vv.
8
9 4 1 7 10 1 6 5
1 2
2 3
1 4
1 5
5 6
5 7
5 8
121
1
1337
0
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:
#include <cstdio>
#include <iostream>
#include <cstring>
#define FOR(x, maxx) for(x = 1; x <= maxx; x++)
#define ZERO(aa, x) memset(aa, x, sizeof(aa))
#define INF 0x3f3f3f3f
#define LL long long
using namespace std; const int MAXN = 2e5+; struct EDGE
{
int v, nxt;
}edge[MAXN<<];
int head[MAXN];
LL sum[MAXN], sumk[MAXN]; int cost[MAXN], dep[MAXN];
int N, cnt;
LL ans, res; void add(int from, int to)
{
edge[cnt].v = to;
edge[cnt].nxt = head[from];
head[from] = cnt++;
}
void init()
{
memset(head, -, sizeof(head));
cnt = ;
ans = ;
} void dfs1(int now, int dh, int fa)
{
//puts("zjy");ans = max(res, ans);
int to;
sum[now] = cost[now];
res += 1LL*cost[now]*dh;
// dep[now] = dh;
// f[now] = fa;
//printf("now: %d\n", now);
for(int i = head[now]; i != -; i = edge[i].nxt){
to = edge[i].v;
if(to != fa){
dfs1(to, dh+, now);
sum[now]+=sum[to];
}
}
} void dfs2(int now, int fa)
{
ans = max(res, ans);
int to;
LL a, b, c;
for(int i = head[now]; i != -; i = edge[i].nxt){
to = edge[i].v;
if(to == fa) continue;
a = sum[now], b = sum[to], c = res;
res-=sum[to]; //当前子树的节点距离-1
res+=sum[now]-sum[to]; //当前非子树节点距离+1
sum[now]-=sum[to];
sum[to] = a;
dfs2(to, now);
sum[now] = a; //还原
sum[to] = b;
res = c;
}
} int main()
{
int i, j;
init();
scanf("%I64d", &N);
FOR(i, N) scanf("%I64d", &cost[i]);
int u, v;
for(i = ; i < N; i++){
scanf("%d %d", &u, &v);
add(u, v);
add(v, u);
}
//puts("zjy");
dfs1(, , ); //第一次递归求初始值
dfs2(, );
printf("%I64d\n", ans);
return ;
}
二、树形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:
#include <cstdio>
#include <iostream>
#include <cstring>
#define FOR(x, maxx) for(x = 1; x <= maxx; x++)
#define ZERO(aa, x) memset(aa, x, sizeof(aa))
#define INF 0x3f3f3f3f
#define LL long long
using namespace std; const int MAXN = 2e5+; struct EDGE
{
int v, nxt;
}edge[MAXN<<];
int head[MAXN], cnt;;
LL sum[MAXN], dp[MAXN];
LL cost[MAXN];
LL ans, res;
LL SSum;
int N; void add(int from, int to)
{
edge[cnt].v = to;
edge[cnt].nxt = head[from];
head[from] = cnt++;
}
void init()
{
memset(head, -, sizeof(head));
memset(dp, , sizeof(dp));
SSum = 0LL;
cnt = ;
ans = ;
} void dfs(int now, int fa)
{
int to;
sum[now] = cost[now];
for(int i = head[now]; i != -; i = edge[i].nxt){
to = edge[i].v;
if(to == fa) continue;
dfs(to, now);
sum[now]+=sum[to];
dp[now] = dp[now] + dp[to] + sum[to];
}
} void solve(int now, int fa)
{
int to;
if(fa) dp[now] = dp[fa]+SSum-*sum[now];
for(int i = head[now]; i != -; i = edge[i].nxt){
to = edge[i].v;
if(to == fa) continue;
solve(to, now);
}
ans = max(ans, dp[now]);
} int main()
{
init();
scanf("%d", &N);
for(int i = ; i <= N; i++){
scanf("%I64d", &cost[i]);
SSum+=cost[i];
}
int u, v;
for(int i = ; i < N; i++){
scanf("%d %d", &u, &v);
add(u, v);
add(v, u);
}
//puts("zjy");
dfs(, ); //第一次递归求初始值
solve(, );
printf("%I64d\n", ans);
return ;
}
Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】的更多相关文章
- 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( ...
- Codeforces Round #499 (Div. 1) F. Tree
Codeforces Round #499 (Div. 1) F. Tree 题目链接 \(\rm CodeForces\):https://codeforces.com/contest/1010/p ...
- 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] ...
- Codeforces Round #135 (Div. 2) D - Choosing Capital for Treeland(两种树形DP)
- 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 ...
- Codeforces Round #527 (Div. 3) ABCDEF题解
Codeforces Round #527 (Div. 3) 题解 题目总链接:https://codeforces.com/contest/1092 A. Uniform String 题意: 输入 ...
- Codeforces Round #485 (Div. 2) F. AND Graph
Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...
- Codeforces Round #486 (Div. 3) F. Rain and Umbrellas
Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/co ...
- Codeforces Round #501 (Div. 3) F. Bracket Substring
题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60 ...
随机推荐
- PHP学习8——图像处理
主要内容: 加载GD库 创建图像 绘制点,线,矩形,多边形,椭圆,弧线 绘制文字 通过GD库生成验证码 其实吧,学习图像方法的最大作用,好像就是为了制作验证码. 所以此专题,不如叫做制作验证码. 1. ...
- Flash流媒体服务器软件
所谓流媒体技术,是指将连续的影像和声音信息经过压缩处理后放在网站服务器上,让用户能够一边下载一边观看.收听(即所谓的“在线欣赏”),而不需要等整个压缩文件下载到自己的机器上才可以欣赏的网络传输技术.目 ...
- centos top 命令详解及退出top命令-使用p键及free命令
1.作用 top命令用来显示执行中的程序进程,使用权限是所有用户. 2.格式 top [-] [d delay] [q] [c] [S] [s] [i] [n] 3.主要参数 d:指定更新的间隔,以秒 ...
- javaweb之EL自定义函数
1.什么是EL自定义函数 EL自定义函数是在EL表达式中调用的某个java类的静态方法,这个静态方法需在web应用程序中进行配置才可以被EL表达式调用.EL自定义函数可以扩展EL表达式的功能,让EL表 ...
- 从Pc转向H5开发遇到的适配问题思考
1.首先说滚动条 移动端开发在不设置任何适配和viewport宽度的情况下,以iphone5为例:屏幕界面的逻辑分辨率是320x568,在谷歌浏览器的界面下屏幕的可视宽度是980px(谷歌设置的,每个 ...
- Bzoj1835:[ZJOI2010]基站选址
Sol 设\(f[i][j]\)表示钦定\(i\)建基站,建了\(j\)个基站的最小代价 \(f[i][j]=max(f[l][j-1]+\Sigma_{t=l+1}^{i-1}\)不能影响到的村庄的 ...
- Python-正则表达式实现计算器功能
需求: 用户输入运算表达式,终端显示计算结果 源代码: # !/usr/bin/env/ python3 # -*- coding: utf-8 -*- """用户输入计 ...
- Linux文件系统简介----转载
原文地址:Linux文件系统 文件系统是linux的一个十分基础的知识,同时也是学习linux的必备知识. 本文将站在一个较高的视图来了解linux的文件系统,主要包括了linux磁盘分区和目录.挂载 ...
- .NET开源工作流RoadFlow-流程运行-运行时监控
流程实例参与者都可以随时查看流程实例的运行情况,如果是待办任务,则在待办事项列表的后面点查看,如果是已完成任务则可以在已办事项列表的后面点查看: 打开之后默认为列表方式显示流程的处理过程,还可以点图形 ...
- 01_Mac下安装homebrew
参考:https://jingyan.baidu.com/album/fec7a1e5ec30341190b4e7e5.html?picindex=3 1.在打开的命令行工具中输入如下语句: ruby ...