bzoj3011
可并堆
复习一下可并堆
维护一个大跟堆,每次把节点儿子打上边权标记,然后合并,可并堆上维护一个size,每次把大于l的弹出,size就是答案
程序中那个d写l和r速度差不多,我写l是表示右儿子到u的最长距离
#include<bits/stdc++.h> using namespace std; const int N = 200010; struct edge { int to; long long w; edge(int to = 0, long long w = 0) : to(to), w(w) {} }; int n; long long L; long long dis[N], tag[N]; int root[N], l[N], r[N], d[N], ans[N], size[N]; vector<edge> G[N]; void pushdown(int x) { if(tag[x] == 0) return; tag[l[x]] += tag[x]; dis[l[x]] += tag[x]; tag[r[x]] += tag[x]; dis[r[x]] += tag[x]; tag[x] = 0; } int merge(int u, int v) { if(!u) return v; if(!v) return u; pushdown(u); pushdown(v); if(dis[u] < dis[v]) swap(u, v); r[u] = merge(r[u], v); if(d[r[u]] > d[l[u]]) swap(l[u], r[u]); d[u] = d[l[u]] + 1; size[u] = size[l[u]] + size[r[u]] + 1; return u; } void dfs(int u) { root[u] = u; size[u] = 1; for(int i = 0; i < G[u].size(); ++i) { edge e = G[u][i]; dfs(e.to); tag[root[e.to]] += e.w; dis[root[e.to]] += e.w; root[u] = merge(root[u], root[e.to]); } while(dis[root[u]] > L && root[u]) root[u] = merge(l[root[u]], r[root[u]]); ans[u] = size[root[u]]; } int main() { scanf("%d%lld", &n, &L); for(int i = 2; i <= n; ++i) { int u; long long len; scanf("%d%lld", &u, &len); G[u].push_back(edge(i, len)); } dfs(1); for(int i = 1; i <= n; ++i) printf("%d\n", ans[i]); return 0; }