LINKc++
給你一棵樹,每一個節點上有一堆餅乾spa
而且告訴你在每一個節點上吃餅乾吃一塊須要多少時間code
而後告訴你通過一條邊的時間遞歸
總時間是T遊戲
兩我的輪流進行,一我的向下選擇子節點行走或者結束遊戲並向上移動吃餅乾,另外一我的割斷一條當前節點到兒子的邊或者什麼都不作get
問第一我的能夠吃到的最大的餅乾的數量it
首先能夠把邊上的時間在dfs的時候拋掉class
而後若是在一個節點上停了下來統計
咱們考慮怎麼統計吃的餅乾,咱們確定會貪心選擇須要時間最少的先吃,這樣才能吃到儘可能多塊移動
而後用線段樹(把單個時間當作下標)維護一下鏈上的全部信息
而後若是在這個節點不停下來,咱們須要遞歸成子問題
顯然第二我的會把往下走dp值最大的一個子樹搞掉,因此當前的dp值就是往下走的第二大和停下來的max
在第一個節點特判一下就行了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N = 1e6 + 10; struct Node { ll v, w; } p[N]; vector<Node> g[N]; ll n, T; #define LD (t << 1) #define RD (t << 1 | 1) ll val[N << 2], siz[N << 2]; void insert(ll t, ll l, ll r, ll pos, ll cursiz) { val[t] += pos * cursiz; siz[t] += cursiz; if (l == r) return; ll mid = (l + r) >> 1; if (pos <= mid) insert(LD, l, mid, pos, cursiz); else insert(RD, mid + 1, r, pos, cursiz); } ll query(ll t, ll l, ll r, ll vl) { if (l == r) return min(siz[t], vl / l); ll mid = (l + r) >> 1; if (val[LD] <= vl) return siz[LD] + query(RD, mid + 1, r, vl - val[LD]); else return query(LD, l, mid, vl); } ll dfs(ll u, ll lef) { insert(1, 1, 1e6, p[u].w, p[u].v); ll res = query(1, 1, 1e6, lef); ll f1 = 0, f2 = 0; for (auto now : g[u]) { ll v = now.v; if (lef <= now.w * 2) continue; ll cur = dfs(v, lef - now.w * 2); if (cur > f1) f2 = f1, f1 = cur; else if (cur > f2) f2 = cur; } insert(1, 1, 1e6, p[u].w, -p[u].v); if (u == 1) return max(res, f1); else return max(res, f2); } int main() { scanf("%lld %lld", &n, &T); for (ll i = 1; i <= n; i++) scanf("%lld", &p[i].v); for (ll i = 1; i <= n; i++) scanf("%lld", &p[i].w); for (ll i = 2; i <= n; i++) { ll u, w; scanf("%lld %lld", &u, &w); g[u].push_back((Node) {i, w}); } printf("%lld", dfs(1, T)); return 0; }