CF #527 (Div. 3) F. Tree with Maximum Cost

F. Tree with Maximum Cost

题目链接: Tree with Maximum Cost

题意

给你一棵N个点的树,每个点有一个权值A[i],现在定义一个MAX值为选定一个点v
∑ i = 1 n d i s t ( i , v ) ∗ A [ i ] \sum ^n_{i = 1} dist(i,v)*A[i] i=1ndist(i,v)A[i]

问这个值最大为多少?

数据范围: N &lt; = 2 ∗ 1 0 5 ; A [ i ] &lt; = 2 ∗ 1 0 5 N&lt;=2*10^5; A[i] &lt;= 2*10^5 N<=2105;A[i]<=2105


思路

假定这个点是一,那么我们可以把这颗树变为以一为根的树,现在每个点对一的贡献为他的深度*他的值,那么我们把这个分散到他们的中间节点,那么每个点所代表的值就是他子树的之和。
a n s = ∑ i = 1 n d i s t ( i , v ) ∗ A [ i ] = ∑ i = 1 n 点 i 的 所 有 子 节 点 和 ans = \sum ^n_{i = 1} dist(i,v)*A[i] = \sum ^n_{i=1}{点i的所有子节点和} ans=i=1ndist(i,v)A[i]=i=1ni
所以我们可以先进行一次dfs来找到每个点的子节点之和,从点一开始,进行转移,每次转移只需要 O ( 1 ) O(1) O(1)的时间

转移公式 now + (sum[1]-sum[v]) - sum[v];


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back

typedef long long ll;
const int MAXN = (int)1e6+7;

int N;
ll A[MAXN];
ll sum[MAXN];
ll ans;
vector<int> G[MAXN];

void dfs(int u,int fa) {
    sum[u] = A[u];
    rep(i,0,G[u].size()-1) {
        int to = G[u][i];
        if (to == fa) continue;
        dfs(to,u);
        sum[u] += sum[to];
    }
}

void getMax(int u,int fa,ll now) {
    ans = max(ans,now);
    rep(i,0,G[u].size()-1) {
        int v = G[u][i];
        if (v == fa) continue;
        ll tmp = now + (sum[1]-sum[v]) - sum[v];
        getMax(to,u,tmp);
    }
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    cin >> N;
    rep(i,1,N) cin >> A[i];
    rep(i,1,N-1) {
        int u,v;
        cin >> u >> v;
        G[u].pb(v);
        G[v].pb(u);
    }

    dfs(1,-1);
    rep(i,2,N) ans += sum[i];
    getMax(1,-1,ans);
    cout << ans << endl;
}

/*
现在给了我一个树
1.预处理出一个树,
每个点都储存着包括自己子树的值和,那么每次转移只需要减去父节点树的值,加上子节点树的值

*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值