题意:给定一颗n(1e5)个点的树,一个时间T(1e18),接下来给你n个数x[i](1e6),表示i节点上有x[i]个饼干,接下来继续给你n个数t[i](1e6)表示i节点上的饼干吃一个要t[i]时间。
现有博弈,你从1节点先手
1.你可以选择走先一个儿子
2.后手断掉一个儿子,不让你走。
走完后回到1,回的时候可以吃一些饼干,问最多能吃多少饼干。
题解:首先考虑到节点v时,最多能吃多少饼干,由于1到v的t[i[,x[i]都知道,贪心取t[i]最小的就好,这一部分可以用线段树来维护。
接下来是博弈的部分,用dp来实现,假设dp[u]表示u子树中的一个节点到u的最大答案。
转移就是:(u!=1)dp[u]=max(dp[u],mx2[v])
(u==1)dp[u]=max(dp[u],mx1[v])
代码:
#include<bits/stdc++.h>
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define ll long long
using namespace std;
const int N=1e6+9;
int n,x[N],t[N];
ll T;
struct Edge{ll v,w,nxt;}e[N<<2];
int head[N],cnt;
inline void add(int u,int v,ll w){
e[cnt]=(Edge){v,w,head[u]};head[u]=cnt++;
}
ll sum[N<<2],g[N<<2];
void update(int p,int l,int r,int qx,int qz){
if(l==r)g[p]+=qz,sum[p]+=1ll*qx*qz;
else{
int mid=(l+r)>>1;
if(qx<=mid)update(ls(p),l,mid,qx,qz);
else update(rs(p),mid+1,r,qx,qz);
g[p]=g[ls(p)]+g[rs(p)],sum[p]=sum[ls(p)]+sum[rs(p)];
}
}
ll query(int p,int l,int r,ll z){
if(l==r)return min(z/l,g[p]);
else{
int mid=(l+r)>>1;
if(z<=sum[ls(p)])return query(ls(p),l,mid,z);
else return g[ls(p)]+query(rs(p),mid+1,r,z-sum[ls(p)]);
}
}
ll dfs(int u,ll T){
// cout<<u<<" "<<T<<endl;
update(1,1,N,t[u],x[u]);
ll ans=query(1,1,N,T),mx1=0,mx2=0;
for(int i=head[u];~i;i=e[i].nxt){
if(T<=2*e[i].w)continue;
ll t=dfs(e[i].v,T-2*e[i].w);
if(t>mx1)mx2=mx1,mx1=t;
else if(t>mx2)mx2=t;
}
if(u==1)ans=max(ans,mx1);
else ans=max(ans,mx2);
// cout<<ans<<endl;
update(1,1,N,t[u],-x[u]);
return ans;
}
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>T;
for(int i=1;i<=n;i++)cin>>x[i];
for(int i=1;i<=n;i++)cin>>t[i];
memset(head,-1,sizeof(head));
for(ll i=2,p,w;i<=n;i++)cin>>p>>w,add(p,i,w);
ll ans=dfs(1,T);
cout<<ans<<endl;
return 0;
}