题目
现在正是Farmer John的农场里面挤奶的季节了!可是奶牛们全都跑了。FJ需要把他们都圈起来,需要你帮他搜寻奶牛。
FJ的农场里有一排N(1<=N<=200,000)个(编号为1..N)的草场,这N个农场由N-1条双向路连接。牛棚在草场1,而且牛棚能通向任意草场。
FJ的奶牛今天早上都在他们的草场上,但谁知道他们现在跑到哪里去了。FJ知道奶牛们只会从牛棚逃出去,而且他们太懒了所以不能跑超过L的距离。对于每个草场,FJ想知道奶牛们能从这个草场出发能到达的多少个不同的草场,使得奶牛们离牛棚更远。
注意:需要用64位整型存储表示距离的值(int64 in Pascal,long long in C/C++,long in Java)。
这题正难则反(这题是弱化版的,直接上就行,强化版的允许往祖先走,再往下其他分支走)
我们可以将每个点对其他点答案的贡献求出来,即往上距离L以内所有点答案+1,这个可以链剖+线段树(或用数组打标记前缀和,这个少个log)
贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#define N 200001
using namespace std;
int n;
long long L;
int b[N][2],h[N],f[4*N],g[N],bz[N],fa[N][18],ans[N],bz1[N];
long long len[N][18];
struct node{
long long dis;
int v,next;
}a[N];
void ins(int x,int y,long long z){
static int sum=0;
a[++sum].v=y,a[sum].dis=z,a[sum].next=g[x],g[x]=sum;
}
void init(){
static int x;
long long y;
scanf("%d %lld",&n,&L);
for (int i=2;i<=n;i++){
scanf("%d %lld",&x,&y);
fa[i][0]=x,len[i][0]=y;
ins(x,i,y);
}
}
void dfs(int x){
for (int i=0;fa[fa[x][i]][i];fa[x][i+1]=fa[fa[x][i]][i],len[x][i+1]=len[x][i]+len[fa[x][i]][i],i++);
for (int i=g[x];i;i=a[i].next){
dfs(a[i].v);
if (b[x][0]<b[a[i].v][0]+1)
b[x][0]=b[a[i].v][0]+1,b[x][1]=a[i].v;
}
}
void dfs1(int x){
static int sum=0;
bz1[bz[x]=++sum]=x;
if (b[x][1])
h[b[x][1]]=h[x],dfs1(b[x][1]);
for (int i=g[x];i;i=a[i].next)
if (a[i].v!=b[x][1])
h[a[i].v]=a[i].v,dfs1(a[i].v);
}
void pre(){
dfs(1);
h[1]=1;
dfs1(1);
}
void change(int l,int r,int s,int ll,int rr){
if (rr<l||r<ll)return;
if (ll<=l&&r<=rr){
++f[s];
return;
}
change(l,(l+r)/2,s+s,ll,rr);
change((l+r)/2+1,r,s+s+1,ll,rr);
}
void up(int x,int y){
while (true)
if (bz[h[x]]<=bz[y]){
change(1,n,1,bz[y],bz[x]);
return;
}else
change(1,n,1,bz[h[x]],bz[x]),x=fa[h[x]][0];
}
int get(int x){
static int i;
static long long y;
y=0,i=17;
while (y+len[x][0]<=L&&x!=1){
for (;y+len[x][i]>L||!fa[x][i];i--);
y+=len[x][i],x=fa[x][i];
}
return x;
}
void build(int l,int r,int s){
if (l==r){
ans[bz1[l]]=f[s];
return;
}
f[s+s]+=f[s],f[s+s+1]+=f[s];
build(l,(l+r)/2,s+s),build((l+r)/2+1,r,s+s+1);
}
void work(){
for (int i=1;i<=n;i++)
up(i,get(i));
build(1,n,1);
}
void write(){
for (int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
int main(){
init();
pre();
work();
write();
return 0;
}