CF77C Beavermuncher-0xFF(树形dp)

这题连写带改了将近一周。。。太弱了。。。很明显是个树形dp,然而细节有点多,蒟蒻认为不太好写。dp[i],表示在i的子树中,先花一个进入i,最后还要回到i,最多能吃多少只。考虑dp[x]如何求出,对于所有儿子y的dp[y],我们贪心的选取,即从大到小排序,先拿大的,再拿小的。要是还能接着拿,看儿子们还有多少剩余,能拿的就是儿子们的剩余与还能拿次数的最小值。注意还有一些回根x而拿掉的1.。。还要注意ll。代码写的丑成一坨,大家凑合看吧。。。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
#define inf 0x3f3f3f3f
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,a[N],rt=0,h[N],num=0,fa[N];//dp[i]--先花一个进入i,最后还要回到i,最多能吃多少只
ll dp[N];
struct edge{
    int to,next;
}data[N<<1];
int dfs(int x){
    dp[x]=1;ll res=0;//剩余
    vector<ll>f;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;if(y==fa[x]) continue;
        fa[y]=x;res+=dfs(y);f.push_back(dp[y]);
    }sort(f.begin(),f.end());
    if(x==rt) a[x]++;//根不需要先花一个进入 
    if(f.size()>=a[x]-1){//不能全拿走 
        for(int i=1;i<=a[x]-1;++i) dp[x]+=f[f.size()-i]+1;return 0;
    }for(int i=0;i<f.size();++i) dp[x]+=f[i]+1;a[x]-=f.size();//全拿走 
    if(a[x]-1>res) return dp[x]+=res*2,a[x]-1-res;//拿剩余 
    else return dp[x]+=(a[x]-1)*2,0;
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read();
        data[++num].to=y;data[num].next=h[x];h[x]=num;
        data[++num].to=x;data[num].next=h[y];h[y]=num;
    }rt=read();dfs(rt);
    printf("%I64d\n",dp[rt]-1);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值