P3306(Running Away From the Barn 可并堆+标记)

题目
题目: 给出以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]);  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值