您的位置:首页 > 其它

[BZOJ3011][Usaco2012 Dec]Running Away From the Barn(可并堆)

2017-01-06 20:56 447 查看

题目描述

传送门

题解

首先这道题是<=而不是<…

在树上自底向上维护左偏树(大根堆),每一个点的权值是点到根的距离

每次将所有的儿子并到父亲上,就代表了一棵子树

如果最大的点的权值已经超过了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
,nxt
,v
;LL c
;
int ls
,rs
,dis
,f
,size
,ans
;LL key
;

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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: