Codeforces Contest 1099 problem F Cookies —— 权值线段树+树形DP

202 篇文章 5 订阅
96 篇文章 1 订阅

Mitya and Vasya are playing an interesting game. They have a rooted tree with n vertices, and the vertices are indexed from 1 to n. The root has index 1. Every other vertex i≥2 has its parent pi, and vertex i is called a child of vertex pi.

There are some cookies in every vertex of the tree: there are xi cookies in vertex i. It takes exactly ti time for Mitya to eat one cookie in vertex i. There is also a chip, which is initially located in the root of the tree, and it takes li time to move the chip along the edge connecting vertex i with its parent.

Mitya and Vasya take turns playing, Mitya goes first.

Mitya moves the chip from the vertex, where the chip is located, to one of its children.
Vasya can remove an edge from the vertex, where the chip is located, to one of its children. Vasya can also decide to skip his turn.
在这里插入图片描述
Mitya can stop the game at any his turn. Once he stops the game, he moves the chip up to the root, eating some cookies along his way. Mitya can decide how many cookies he would like to eat in every vertex on his way. The total time spent on descend, ascend and eating cookies should not exceed T. Please note that in the end of the game the chip is always located in the root of the tree: Mitya can not leave the chip in any other vertex, even if he has already eaten enough cookies — he must move the chip back to the root (and every move from vertex v to its parent takes lv time).

Find out what is the maximum number of cookies Mitya can eat, regardless of Vasya’s actions.

Input
The first line contains two integers n and T — the number of vertices in the tree and the time he has to accomplish his task (2≤n≤105; 1≤T≤1018).

The second line contains n integers x1, x2, …, xn — number of cookies located in the corresponding vertex (1≤xi≤106). The third line contains n integers t1, t2, …, tn — how much time it takes Mitya to eat one cookie in vertex i (1≤ti≤106).

Each of the following n−1 lines describe the tree. For every i from 2 to n, the corresponding line contains two integers pi and li, where pi denotes the parent of vertex i and li denotes the time it takes Mitya to move the chip along the edge from vertex i to its parent (1≤pi<i, 0≤li≤109).

Output
Output a single integer — maximum number of cookies Mitya can eat.

Examples
inputCopy
5 26
1 5 1 7 7
1 3 2 2 2
1 1
1 1
2 0
2 0
outputCopy
11
inputCopy
3 179
2 2 1
6 6 6
1 3
2 3
outputCopy
4
Note
In the first example test case, Mitya can start by moving the chip to vertex 2. In this case no matter how Vasya plays, Mitya is able to eat at least 11 cookies. Below you can find the detailed description of the moves:

Mitya moves chip to vertex 2.
Vasya removes edge to vertex 4.
Mitya moves chip to vertex 5.
Since vertex 5 has no children, Vasya does not remove any edges.
Mitya stops the game and moves the chip towards the root, eating cookies along the way (7 in vertex 5, 3 in vertex 2, 1 in vertex 1).
Mitya spend 1+0 time to go down, 0+1 to go up, 7⋅2 to eat 7 cookies in vertex 5, 3⋅3 to eat 3 cookies in vertex 2, 1⋅1 to eat 1 cookie in vertex 1. Total time is 1+0+0+1+7⋅2+3⋅3+1⋅1=26.

题意:

给你一棵树有n个节点,每个节点上有xi个饼干,每个节点上吃饼干吃一块需要ti时间再给你每个节点的父亲,和经过这条边所花费时间,刚开始你在起点,两个人轮流进行以下步骤,你先手
你:移动到子节点,或者结束游戏并移动到根节点,选择性吃沿途饼干
对手:删一条你所在节点到儿子的边,或者什么都不做
求你能最多吃掉的饼干数。

注意:对手是会做出让你吃掉饼干数目最少的决策

题解:

看到这道题目就知道是dfs找所有的点,那么对于儿子节点我们怎么知道当前有哪些饼干呢?一开始想到了set,因为它可以添加查找删除,但是set的时间复杂度可能会比较高,就没敢用,后来想到了用权值线段树来维护dfs到当前的时候的情况,sum记录吃掉这个区间所有饼干需要的时间,num表示这个区间有多少饼干,由于对手的存在,我们要返回的是dfs出来第二大的数,但是由于你先手,那么对于在1这个点,可以取到最大的情况。1e6的数据范围,,不离散化也无妨

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
ll sum[N*4],num[N*4];
int cnt,head[N];
ll x[N],t[N],a[N],T;
void push_up(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
    num[root]=num[root<<1]+num[root<<1|1];
}
void update(int l,int r,int root,ll pos,ll n)
{
    if(l==r)
    {
        sum[root]+=a[pos]*n;
        num[root]+=n;
        return ;
    }
    int mid=l+r>>1;
    if(mid>=pos)
        update(l,mid,root<<1,pos,n);
    else
        update(mid+1,r,root<<1|1,pos,n);
    push_up(root);
}
ll query(int l,int r,int root,ll s)
{
    if(sum[root]<=s)
        return num[root];
    if(l==r)
        return s/a[l];
    int mid=l+r>>1;
    ll ans=query(l,mid,root<<1,s);
    if(sum[root<<1]<s)
        ans+=query(mid+1,r,root<<1|1,s-sum[root<<1]);
    return ans;
}

struct node
{
    int to,next;
    ll w;
}e[N];
void add(int x,int y,ll w)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    e[cnt].w=w;
    head[x]=cnt++;
}
ll dp[N];
ll dfs(int now,ll tim)
{
    update(1,N-1,1,t[now],x[now]);
    //ans=max(ans,query(1,N-1,1,T-tim*2));
    ll m=query(1,N-1,1,T-tim*2);
    ll m1=0,m2=0;
    for(int i=head[now];~i;i=e[i].next)
    {
        if((tim+e[i].w)*2>T)
            continue;
        
        ll ans=dfs(e[i].to,tim+e[i].w);
        if(ans>m1)
            m2=m1,m1=ans;
        else
            m2=max(m2,ans);
    }
    update(1,N-1,1,t[now],-x[now]);
    if(now==1)
        return max(m,m1);
    else
        return max(m,m2);
}
int main()
{
    memset(head,-1,sizeof(head));
    int n;
    scanf("%d%lld",&n,&T);
    for(int i=1;i<=n;i++)
        scanf("%lld",&x[i]);
    for(int i=1;i<=n;i++)
        scanf("%lld",&t[i]),a[i]=t[i];
    sort(a+1,a+1+n);
    int all=unique(a+1,a+1+n)-a-1;
    for(int i=1;i<=n;i++)
        t[i]=lower_bound(a+1,a+1+all,t[i])-a;
    int fa;
    ll l;
    for(int i=2;i<=n;i++)
        scanf("%d%lld",&fa,&l),add(fa,i,l);
    printf("%lld\n",dfs(1,0));
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值