Codeforces1099F. Cookies【DP】【線段樹】【貪心】【博弈】【沙比提(這是啥算法)】

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;
}
相關文章
相關標籤/搜索