Codeforces 1637 F. Towers —— 思维,dfs

82 篇文章 1 订阅

This way

题意:

给你一棵树,每个点都有一个值a[i]。你要在一些点上放值b[i],使得对于任意一个点x,都有两个点u,v:x在u,v的路径上且min(b[u],b[v])>=a[x]。
问你最少的b之和是多少。

题解:

我把ne写成了x,找了半个小时的bug。
我们只需要将a最大的点当成根rt,然后对于任意一个x(x!=rt),只需要它的子树中有一个b>=a[x]即可。
因为在最后我们需要两个点的值>=a[rt],那么对于任意一个x(x!=rt)来说,必然至少有一个点不在它的子树中。
我们记录mx[x]表示当前子树中b的最大值,smx表示区别于mx的其它子树中的最大值。
如果当前是根的话,那么就需要有两个点来支撑他,否则只需要一个点即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
vector<int>vec[N];
int a[N],mx[N],smx[N],rt;
ll ans;
void dfs(int x,int fa){
    if(x-rt&&vec[x].size()==1)mx[x]=a[x],ans+=a[x];
    for(int ne:vec[x]){
        if(ne==fa)continue;
        dfs(ne,x);
        if(mx[ne]>mx[x])smx[x]=mx[x],mx[x]=mx[ne];
        else if(mx[ne]>smx[x])smx[x]=mx[ne];
    }
    if(x-rt){
        if(mx[x]<a[x])
            ans+=a[x]-mx[x],mx[x]=a[x];
    }
    else{
        if(!smx[x])ans+=a[x]+a[x]-mx[x];
        else ans+=a[x]*2-mx[x]-smx[x];
    }
}
int main()
{
    int n,x,y;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),rt=a[rt]>=a[i]?rt:i;
    for(int i=1;i<n;i++)
        scanf("%d%d",&x,&y),vec[x].push_back(y),vec[y].push_back(x);
    dfs(rt,0);
    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值