题目描述
题解
首先这道题是<=而不是<…
在树上自底向上维护左偏树(大根堆),每一个点的权值是点到根的距离
每次将所有的儿子并到父亲上,就代表了一棵子树
如果最大的点的权值已经超过了l的话就弹顶
再动态维护一下size
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdio>
using namespace std;
#define LL long long
#define N 200005
int n;
LL l;
int tot,point[N],nxt[N],v[N];LL c[N];
int ls[N],rs[N],dis[N],f[N],size[N],ans[N];LL key[N];
void add(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 (x==f[x]) return x;
f[x]=find(f[x]);
return f[x];
}
int merge(int x,int y)
{
if (!x) return y;
if (!y) return x;
if (key[x]<key[y]) swap(x,y);
rs[x]=merge(rs[x],y);
if (dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[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)
{
int fx,fy,top,tmp;
for (int i=point[x];i;i=nxt[i])
{
int u=v[i];
key[v[i]]=key[x]+c[i];
dfs(v[i]);
fx=find(x),fy=find(v[i]);
top=merge(fx,fy);
f[fx]=f[fy]=top;
size[top]=size[fx]+size[fy];
while (key[top]-key[x]>=l)
{
tmp=pop(top);
size[tmp]=size[top]-1;
top=tmp;
}
}
ans[x]=size[find(x)];
}
int main()
{
scanf("%d%I64d",&n,&l);
for (int i=2;i<=n;++i)
{
int fa;LL z;
scanf("%d%I64d",&fa,&z);
add(fa,i,z);
}
for (int i=1;i<=n;++i) f[i]=i,size[i]=1;
dfs(1);
for (int i=1;i<=n;++i)
printf("%d\n",ans[i]);
}