传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=3011
一想到这个第一反应是树形dp,然后10^18 (' ' ) 所以我直接搞了一个左偏树往上面不断合并(' ' ) 网上好像有人用的线段树维护区间(子树)最小值,不过我觉得我这个做法比较好写吧。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 210000; struct node { ll val, size, dis, lazy; node *l, *r; }e[maxn * 8]; ll ne = 0; void swap(node *&a, node* &b) { node* t = a; a = b, b = t; } void test(node* x) { if(x) { cout << x-> val <<" "<< x-> size << endl; test(x-> l), test(x-> r); } } void update(node *x) { x-> size = 1; if(x-> l) x-> size += x-> l-> size; if(x-> r) x-> size += x-> r-> size; } void pushdown(node* x) { if(!x || !x-> lazy) return; if(x-> l) x-> l-> val += x-> lazy, x-> l-> lazy += x-> lazy; if(x-> r) x-> r-> val += x-> lazy, x-> r-> lazy += x-> lazy; x-> lazy = 0; } node* merge(node* a, node *b) { if(!a) return b; if(!b) return a; pushdown(a), pushdown(b); if(a-> val < b-> val) swap(a, b); a-> r = merge(a-> r, b); ll dl = a-> l ? a-> l-> dis : -1; ll dr = a-> r ? a-> r-> dis : -1; if(dl < dr) swap(a-> l, a-> r); a-> dis = a-> r ? a-> r-> dis + 1 : 0; update(a); return a; } void pop(node* &x) { pushdown(x); x = merge(x-> l, x-> r); } ll n, m; struct edge { ll t, d; edge* next; }se[maxn * 2], *head[maxn]; ll oe = 0; void addedge(ll f, ll t, ll d) { se[oe].t = t, se[oe].d = d, se[oe].next = head[f], head[f] = se + oe ++; } ll int_get() { ll x = 0; char c = (char)getchar(); bool f = 0; while(!isdigit(c)) { if(c == '-') f = 1; c = (char)getchar(); } while(isdigit(c)) { x = x * 10 + (int)(c - '0'); c = (char)getchar(); } if(f) x= -x; return x; } void read() { n = int_get(); m = int_get(); for(ll i = 2; i <= n; ++ i) { ll f, w; f = int_get(), w = int_get(); addedge(i, f, w), addedge(f, i, w); } } ll s[maxn], top = 0; node* rt[maxn]; ll h[maxn]; void dfs(ll x, ll fa) { h[x] = h[fa] + 1; for(edge* p = head[x]; p; p = p-> next) { if(p-> t != fa) dfs(p-> t, x); } s[++ top] = x; } ll ans[maxn]; void sov() { dfs(1, 0); for(ll j = 1; j <= top; ++ j) { ll i = s[j]; rt[i] = e + ne ++; rt[i]-> dis = 0; rt[i]-> val = 0; rt[i]-> size = 1; for(edge* p = head[i]; p; p = p-> next) { if(h[p-> t] > h[i]) { if(rt[p-> t]) rt[p-> t]-> lazy += p-> d, rt[p-> t]-> val += p-> d; rt[i] = merge(rt[i], rt[p-> t]); } } while(rt[i] && rt[i]-> val > m) pop(rt[i]); ans[i] += rt[i] ? rt[i]-> size : 0; } for(ll i = 1; i <= n; ++ i) printf("%lld\n", ans[i]); } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); read(), sov(); return 0; }