Processing math: 100%

BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆

BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆

Description

给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于l的点有多少个。

Sample Input

4 5
1 4
2 3
1 5

Sample Output

3
2
1
1


 

做法不唯一,这里用来练习可并堆。

先求出每个点i 到根路径上的长度dis[i] ,对每个点建一个可并堆(大根)。

然后从下往上合并,如果当前dis[]dis[x]>L 就弹出,记录每个节点最后剩下的点数即可。

 

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 200050
typedef long long ll;
ll val[N<<1],L,v[N];
int head[N],to[N<<1],nxt[N<<1],cnt,n,root[N],ls[N],rs[N],dis[N],siz[N];
inline void add(int u,int v,ll w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
int merge(int x,int y) {
    if(!x) return y;
    if(!y) return x;
    if(v[x]<v[y]) swap(x,y);
    rs[x]=merge(rs[x],y);
    if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
    dis[x]=dis[rs[x]]+1;
    return x;
}
void dfs(int x,int y) {
    int i;
    siz[x]=1; root[x]=x;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            v[to[i]]=v[x]+val[i];
            dfs(to[i],x);
            siz[x]+=siz[to[i]];
            root[x]=merge(root[x],root[to[i]]);
        }
    }
    while(v[root[x]]-v[x]>L) {
        siz[x]--; root[x]=merge(ls[root[x]],rs[root[x]]);      
    }
}
int main() {
    dis[0]=-1;
    scanf("%d%lld",&n,&L);
    int i,x;
    ll y;
    for(i=2;i<=n;i++) {
        scanf("%d%lld",&x,&y);
        add(i,x,y); add(x,i,y);
    }
    dfs(1,0);
    for(i=1;i<=n;i++) {
        printf("%d\n",siz[i]); 
    }
}

 

posted @   fcwww  阅读(127)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
阅读排行:
· 对象命名为何需要避免'-er'和'-or'后缀
· JDK 24 发布,新特性解读!
· Java24你发任你发,我用Java8
· .NET Core奇技淫巧之WinForm使用Python.NET并打包
· C# 中比较实用的关键字,基础高频面试题!
点击右上角即可分享
微信分享提示