题目
题目: 给出以1为根的一棵有根树,问每个点的子树中与它距离<=l的点有多少个。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct Edge{int to;ll len;int nex;}edge[N<<1];int head[N],tot;
void add(int from,int to,ll len){
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
edge[++tot]=(Edge){from,len,head[to]};head[to]=tot;
}
int ls[N],rs[N],f[N],dis[N],sz[N],ans[N],n;ll dep[N],tag[N],K;
void pushdown(int x){
if(!tag[x]) return;
if(ls[x]) dep[ls[x]]+=tag[x],tag[ls[x]]+=tag[x];
if(rs[x]) dep[rs[x]]+=tag[x],tag[rs[x]]+=tag[x];
tag[x]=0;
}
int combine(int x,int y){
if(!x||!y) return x+y;
if(dep[x]<dep[y]) swap(x,y);
pushdown(x);//要合并rs[x]与y,故pushdown。
rs[x]=combine(rs[x],y);
if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
dis[x]=dis[rs[x]]+1;
sz[x]=sz[ls[x]]+sz[rs[x]]+1;
return x;
}
void dfs(int x,int fa){
sz[x]=1,dis[x]=0,f[x]=x;
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].to;
if(y==fa) continue;
dfs(y,x),dep[f[y]]+=edge[i].len,tag[f[y]]+=edge[i].len;
while(dep[f[y]]>K){//将y这颗子树里面的顶点依次删除假如dep[top]>K时;
pushdown(f[y]);//要将f[y]删除了,但是f[y]仍然有tag标记,tag下推。
f[y]=combine(ls[f[y]],rs[f[y]]);//永远保证f[y]就是y所在堆的top.
}
f[x]=combine(f[x],f[y]);//用所有是关于x儿子y子树的堆合并成是x的子树的堆。
}
ans[x]=sz[f[x]];
}
int main(){
scanf("%d%lld",&n,&K);
for(int i=2;i<=n;++i){int y;ll w;scanf("%d%lld",&y,&w);add(i,y,w);}
dfs(1,1);
for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
}