题目:
题解:
自底向上维护左偏树(大根堆),每个点的权值是到根的距离
每次对于一个点x,把所有子节点merge到一起就代表这棵子树
如果堆顶的权值差>L就pop,动态地维护size
代码:
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
const int N=200005;
int tot,nxt[N],point[N],v[N],size[N],f[N],ls[N],rs[N],dis[N],ans[N];
LL c[N],a[N],l;
void addline(int x,int y,LL z){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}
int find(int x){if (f[x]!=x) f[x]=find(f[x]); return f[x];}
int merge(int x,int y)
{
if (!x || !y) return x+y;
if (a[x]<a[y]) swap(x,y);
rs[x]=merge(rs[x],y);
if (dis[ls[x]]<dis[rs[x]]) swap(rs[x],ls[x]);
if (!rs[x]) dis[x]=0;else dis[x]=dis[rs[x]]+1;
return x;
}
int pop(int x)
{
f[x]=merge(ls[x],rs[x]);
f[f[x]]=f[x];
ls[x]=rs[x]=dis[x]=0;
return f[x];
}
void dfs(int x)
{
for (int i=point[x];i;i=nxt[i])
{
a[v[i]]=a[x]+c[i];
dfs(v[i]);
int fx=find(x),fy=find(v[i]);
int top=merge(fx,fy); f[fx]=f[fy]=top;
size[top]=size[fx]+size[fy];
while (a[top]-a[x]>l)
{
int tmp=pop(top);
size[tmp]=size[top]-1;
top=tmp;
}
}
ans[x]=size[find(x)];
}
int main()
{
int n;scanf("%d%lld",&n,&l);
for (int i=2;i<=n;i++)
{
int x;LL y;scanf("%d%lld",&x,&y);
addline(x,i,y);
}
for (int i=1;i<=n;i++) size[i]=1,f[i]=i;
dfs(1);
for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
}