P3066 [USACO12DEC] Running Away From the Barn G

P3066 [USACO12DEC] Running Away From the Barn G

题目描述

给定一颗 n 个点的有根树,边有边权,节点从 1n 编号,1 号节点是这棵树的根。

再给出一个参数 t,对于树上的每个节点 u,请求出 u 的子树中有多少节点满足该节点到 u 的距离不大于 t

输入格式

输入的第一行是两个整数,分别表示节点数 n 和给出的参数 t

2 到第 n 行,每行两个整数,第 i 行的整数 pi,wi 表示节点 i 的父节点为 pi,连结 ipi 的边的边权为 wi

输出格式

输出 n 行,每行一个整数,第 i 行的整数表示 i 的子树内到 i 的距离不大于 t 的节点个数。

数据规模与约定

对于全部的测试点,保证:

  • 1n2×1051t1018
  • 1pi<i1wi1012

Solution:

线段树合并板子捏。

我们先对这整颗树求出每个点到根的距离 disu 然后对每个节点开一颗权值线段树,维护当前子树下的每个 dis 区间内的点的个数,那么到u距离不超过t就等价于:

dis[0,disu+t]

然后我们发现每个点都开一颗权值线段树然后遍历子树更新肯定是不行的,所以我们需要线段树合并。

然后这题就做完了

然后这题貌似还有个弱化版本this

Code:

#include<bits/stdc++.h>
#define int long long
const int N=2e5+5;
const int inf=1e17;
using namespace std;
struct Segment_Tree{
int cnt,rt[N];
struct Tree{
int ls,rs,cnt;
}t[N*40];
void pushup(int x)
{
t[x].cnt=t[t[x].ls].cnt+t[t[x].rs].cnt;
}
void insert(int &x,int l,int r,int pos)
{
if(!x)x=++cnt;
t[x].cnt++;
if(l==r)return;
int mid=l+r>>1;
if(pos<=mid)insert(t[x].ls,l,mid,pos);
if(mid<pos) insert(t[x].rs,mid+1,r,pos);
}
int merge(int x,int y,int l,int r)
{
if(!x||!y)return x|y;
if(l==r)
{
t[x].cnt+=t[y].cnt;
return x;
}
int mid=l+r>>1;
t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r);
pushup(x);
return x;
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
//cout<<"query:"<<l<<" "<<r<<"="<<t[x].cnt<<"\n";
return t[x].cnt;
}
int mid=l+r>>1,res=0;
if(L<=mid)res+=query(t[x].ls,l,mid,L,R);
if(mid<R)res+=query(t[x].rs,mid+1,r,L,R);
return res;
}
}T;
int n,m;
vector<tuple<int,int> > E[N];
int dis[N],a[N],b[N],ans[N];
void dfs(int x)
{
for(auto [y,w] :E[x])
{
dis[y]=dis[x]+w;
dfs(y);
}
}
void calc(int x)
{
T.insert(T.rt[x],1,n,dis[x]);
//cout<<"upd:"<<T.rt[x]<<" "<<dis[x]<<"\n";
for(auto [y,w] : E[x])
{
calc(y);
//cout<<"merge:"<<x<<" "<<y<<"="<<T.rt[x]<<" "<<T.rt[y]<<"\n";
T.rt[x]=T.merge(T.rt[x],T.rt[y],1,n);
}
ans[x]=T.query(T.rt[x],1,n,1,a[x]);
//cout<<"ans : "<<x<<" : "<<dis[x]<<"="<<ans[x]<<"\n";
}
void work()
{
cin>>n>>m;
for(int i=1,x,y;i<n;i++)
{
scanf("%lld%lld",&x,&y);
E[x].emplace_back(i+1,y);
}
dfs(1);
for(int i=1;i<=n;i++)b[i]=dis[i];
b[n+1]=inf;
sort(b+1,b+2+n);
int tot=unique(b+1,b+2+n)-(b+1);
for(int i=1;i<=n;i++)
{
a[i]=dis[i]+m;
int k=lower_bound(b+1,b+1+tot,dis[i])-b-1,kk=lower_bound(b+1,b+1+tot,a[i])-b-1;
dis[i]= dis[i]==b[k+1] ? k+1 : k;
a[i]= a[i]==b[kk+1] ? kk+1 : kk;
}
calc(1);
for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
}
#undef int
int main()
{
//freopen("run.in","r",stdin);
//freopen("run.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示