期末考前写题解,(rp++! rp++! rp++!)
[description
]
给出一个以 (1) 为根的边带权有根树,给定一个参数 (L) ,问每个点的子树中与它距离小于等于 (L) 的节点个数。
[solution
]
有关子树内的统计,肯定能联想到 线段树合并 吧。
记 (d[u]) 表示根节点到 (u) 的距离,该数组可通过一次遍历求出。
则对于每个点 (u) ,它的贡献就是满足下式的点对数量:
[d[v]-d[u]leq L { vinoperatorname{subtree}(u) }
]
移项,可化简为:
[d[v]leq d[u]+L { vinoperatorname{subtree}(u) }
]
那么问题就转化成了:
令点 (u) 的点权为 (d[u])。对于每个点 (u) ,求出该点的子树中点权小于等于 (d[u]+L) 的节点个数
然后发现是一道 线段树合并 板子题,直接码上就行。
需注意的是,这个 (L) 和 (d[~]) 的范围有 (1e18) ,所以我们需要离散化一下防止 (MLE) 。
我是把每个 (d[u]) 以及 (d[u]+L) 都扔进去离散化了,如果有哪位 (dalao) 有更优秀的离散化方法,可以评论在博客下方,我会感激不尽。
[code
]
#include<cstdio>
#include<algorithm>
#define RI register int
using namespace std;
const int N=200100,M=200100,MLOGN=10001000;
int n,m;
long long L;
int Etot,head[N],ver[M],Next[M];
long long edge[M];
void add(int u,int v,long long w)
{
ver[++Etot]=v; edge[Etot]=w; Next[Etot]=head[u]; head[u]=Etot;
}
long long d[N];
int len;
long long mapval[1000100];
void discrete()
{
sort(mapval+1,mapval+1+len);
len=unique(mapval+1,mapval+1+len)-mapval-1;
}
int query(long long x)
{
return lower_bound(mapval+1,mapval+1+len,x)-mapval;
}
int tot,root[N];
struct SegmentTree{
int lc,rc;
int cnt;
}t[MLOGN];
int New()
{
tot++;
t[tot].lc=t[tot].rc=t[tot].cnt=0;
return tot;
}
void insert(int &p,int l,int r,int delta,int val)
{
if(!p)p=New();
t[p].cnt+=val;
if(l==r)return;
int mid=(l+r)/2;
if(delta<=mid)
insert(t[p].lc,l,mid,delta,val);
else
insert(t[p].rc,mid+1,r,delta,val);
}
int merge(int p,int q)
{
if(!p||!q)return p^q;
t[p].cnt+=t[q].cnt;
t[p].lc=merge(t[p].lc,t[q].lc);
t[p].rc=merge(t[p].rc,t[q].rc);
return p;
}
int ask(int p,int l,int r,int s,int e)
{
if(!p)return 0;
if(s<=l&&r<=e)return t[p].cnt;
int mid=(l+r)/2;
int val=0;
if(s<=mid)
val+=ask(t[p].lc,l,mid,s,e);
if(mid<e)
val+=ask(t[p].rc,mid+1,r,s,e);
return val;
}
void dfs1(int u)
{
mapval[++len]=d[u],mapval[++len]=d[u]+L;
for(RI i=head[u];i;i=Next[i])
{
int v=ver[i];
long long w=edge[i];
d[v]=d[u]+w;
dfs1(v);
}
}
int ans[N];
void dfs2(int u)
{
for(RI i=head[u];i;i=Next[i])
{
int v=ver[i];
dfs2(v);
root[u]=merge(root[u],root[v]);
}
insert(root[u],1,len,query(d[u]),1);
ans[u]=ask(root[u],1,len,1,query(d[u]+L));
}
int main()
{
scanf("%d%lld",&n,&L);
for(RI i=2;i<=n;i++)
{
int fa;
long long w;
scanf("%d%lld",&fa,&w);
add(fa,i,w);
}
dfs1(1);
discrete();
dfs2(1);
for(RI i=1;i<=n;i++)
printf("%d
",ans[i]);
return 0;
}
[thanks for watching
]