1. 程式人生 > >Codeforces Round #530 (Div. 2) E (樹形dp+線段樹)

Codeforces Round #530 (Div. 2) E (樹形dp+線段樹)

scanf 思路 玩家 == dfs class num 鏈接 節點

鏈接:

題意:

給你一棵樹,樹上有n個節點,每個節點上有ai塊餅幹,在這個節點上的每塊餅幹需要花費bi時間,有兩個玩家,玩家一可以移動到當前點的子節點也可以申請遊戲結束返回根節點並吃沿途的餅幹,玩家二可以刪除當前點到兒子節點的一條邊,走路和吃餅幹都消耗時間,會給出一個總時間,在總時間內盡可能的多吃餅幹,問最多能吃多少個?

思路:

由於是玩家一先手,那麽最開始的最大邊則不會被刪除,但之後路途的最大邊都會被玩家二刪除,所以我們對於當前點我們需要求:

1.如果現在回頭那麽最多可以吃到多少餅幹

2.向下走最多可以吃到多少餅幹

3.向下走次多可以吃到多少餅幹

實現代碼:

#include<bits/stdc++.h>
using
namespace std; #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mid ll m = (l + r) >> 1 const ll M = 1e6+10; const ll Max = 1e6; struct node{ ll to,w,next; }e[M<<1]; ll sum[M<<2],num[M<<2],a[M],tim[M],head[M],cnt; void
add(ll u,ll v,ll w){ e[++cnt].to = v;e[cnt].next = head[u];e[cnt].w = w;head[u] = cnt; } void pushup(ll rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; num[rt] = num[rt<<1] + num[rt<<1|1]; } void update(ll p,ll c,ll l,ll r,ll rt){ if(l == r){ sum[rt]
+= p*c; num[rt] += c; return ; } mid; if(p <= m) update(p,c,lson); else update(p,c,rson); pushup(rt); } ll query(ll t,ll l,ll r,ll rt){ if(sum[rt] <= t) return num[rt]; if(l == r){ return t/l; } mid; if(sum[rt<<1] >= t) return query(t,lson); else return num[rt<<1] + query(t-sum[rt<<1],rson); } ll dfs(ll u,ll fa,ll t){ update(tim[u],a[u],1,Max,1); ll f1 = query(t,1,Max,1); ll f2 = 0,f3 = 0; for(ll i = head[u];i;i=e[i].next){ ll v = e[i].to; if(v == fa) continue; if(t <= e[i].w*2) continue; ll k = dfs(v,u,t-e[i].w*2); if(k > f2) f3 = f2,f2 = k; else if(k > f3) f3 = k; } update(tim[u],-a[u],1,Max,1); if(u == 1) return max(f1,f2); else return max(f1,f3); } int main() { ll n,T,x,y; scanf("%lld%lld",&n,&T); for(ll i = 1;i <= n;i ++) scanf("%lld",&a[i]); for(ll i = 1;i <= n;i ++) scanf("%lld",&tim[i]); for(ll i = 2;i <= n;i ++){ scanf("%lld%lld",&x,&y); add(i,x,y); add(x,i,y); } printf("%lld\n",dfs(1,0,T)); return 0; }

Codeforces Round #530 (Div. 2) E (樹形dp+線段樹)