CF1099F Cookies

线段树二分+最优解和次优解处理

题目
因为两人都足够聪明,所以V肯定会剪掉最优解,因此除了根以外,其他点都要剪掉最优解。同时,M只能选择一条路径来走,考虑在每个点都当作路径的终点,每次快速的统计一下答案。M肯定是在花费少的地方买的越多越好,要动态维护这个路径的变化,考虑用线段树来维护前缀和。每次用子树的次优解来更新当前解。
线段树用花费来进行下标建树,每次尽快选靠近左边的点

#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define int long long
using namespace std;
const int N = 1e5+100,M=1e6+10;
vector<pii>g[N];
ll nx[N],tx[N];
ll mx[N][2];
int rt,tot;
struct T{
    int lc[M<<2],rc[M<<2];
    ll sum[M<<2],num[M<<2];
    //以时间为下标进行线段树建树
    void update(int &c,int l,int r,ll pos,int k){
        if(!c) c=++tot;
        if(l==r){
            num[c]+=k;
            sum[c]+=pos*k;
            return;
        }
        ll mid = l+r>>1;
        if(pos<=mid) update(lc[c],l,mid,pos,k);
        else update(rc[c],mid+1,r,pos,k);
        sum[c]=sum[lc[c]]+sum[rc[c]];
        num[c]=num[lc[c]]+num[rc[c]];
    }
    ll query(int c,int l,int r,ll t){
        if(!rt) return 0;
        if(sum[c]<=t) return num[c];
        if(l==r){
           return t/l;
        }
        int mid =l+r>>1;
        if(sum[lc[c]]<=t){
            return num[lc[c]]+query(rc[c],mid+1,r,t-sum[lc[c]]);
        }
        else return query(lc[c],l,mid,t);
    }
}b;
ll res,ans[N];
void dfs(int u,ll T){
    b.update(rt,1,1e6,tx[u],nx[u]);
    ans[u]=b.query(rt,1,1e6,T);
    for(auto[to,w]:g[u]){
        if(T-2*w>0) dfs(to,T-2*w);
        else continue;
        if(mx[u][0]>ans[to]) mx[u][1]=max(ans[to],mx[u][1]);
        else mx[u][1]=mx[u][0],mx[u][0]=ans[to];
    }
    if(u==1) ans[u]=max(ans[u],mx[u][0]);
    else ans[u]=max(ans[u],mx[u][1]);
    b.update(rt,1,1e6,tx[u],-nx[u]);
}
signed main(){
    ll n,T;
    cin>>n>>T;
    for(int i=1;i<=n;i++){
        cin>>nx[i];
    }
    for(int i=1;i<=n;i++){
        cin>>tx[i];
    }
    for(int i=2;i<=n;i++){
        int f,l;
        cin>>f>>l;
        g[f].push_back({i,l});
    }
    dfs(1,T);
    cout<<ans[1]<<'\n';
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值