4123 - Bob’s Race

如果没有求点权,就是个RMQ的版。
至于点权,可以不用树形dp,直接求到直径的两个端点距离的较大值就好了。证明略。
一次AC美滋滋。
#pragma GCC optimize("O2")
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define G getchar()
#define LL long long
#define pll pair<int,int>
#define mkp make_pair
#define X first
#define Y second
const int N=50005;
int n,m;
int he[N],tot,ne[N<<1],to[N<<1],W[N<<1];
int dep[N],dep2[N],rt,rt2,dad[N],son[N],sz[N],pre[N];
int Max[N][17],Min[N][17],nxt[N][17],cs,bit[N];
inline void read(int &x){ 
 char ch=G;//int f=1; 
 for(;ch>57||ch<48;ch=G);//if(ch==45)f=-1; 
 for(x=0;ch>=48&&ch<=57;ch=G)x=x*10+ch-48; 
 //x*=f; 
}
void add(int x,int y,int z){
 to[++tot]=y;W[tot]=z;ne[tot]=he[x];he[x]=tot;
}
void DFS(int x,int e){
 int i,y;
 for(i=he[x];i;i=ne[i])if(i!=e){
  dep[y=to[i]]=dep[x]+W[i];DFS(y,i^1);
 }
}
void DFS1(int x,int e){
 int i,y;sz[x]=1;dep2[x]=dep2[pre[x]=to[e]]+1;
 for(i=he[x];i;i=ne[i])if(i!=e){
  dep[y=to[i]]=dep[x]+W[i];
  DFS1(y,i^1);
  if(sz[son[x]]<sz[y])son[x]=y;
  sz[x]+=sz[y];
 }
}
void DFS2(int x){
 int i,y;
 dad[x]=son[pre[x]]==x?dad[pre[x]]:x;
 for(i=he[x];i;i=ne[i])if((y=to[i])!=pre[x])
  DFS2(y);
}
int lca(int x,int y){
 int fx=dad[x],fy=dad[y];
 while(fx!=fy){
  if(dep2[fx]>dep2[fy])fx=dad[x=pre[fx]];
  else fy=dad[y=pre[fy]];
 }
 return dep2[x]<dep2[y]?x:y;
}
int dis(int x,int y){
 return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
}
int get(int x,int y){
 int t=bit[y-x+1];
 y-=(1<<t)-1;
 return max(Max[x][t],Max[y][t])-min(Min[x][t],Min[y][t]);
}
int main(){
 int i,x,y,z,t;
 for(t=0,x=1;x<=50000;x<<=1)bit[x]=t++;
 rep(x,3,50000)if(!bit[x])bit[x]=bit[x-1];
 while(1){
  read(n);read(m);
  if(!n&&!m)return 0;
  tot=1;rep(i,1,n)he[i]=0;
  rep(i,2,n){
   read(x);read(y);read(z);
   add(x,y,z);add(y,x,z);
  }
  dep[1]=0;DFS(rt=1,0);
  rep(x,2,n)if(dep[x]>dep[rt])rt=x;
  dep[rt]=dep2[rt]=0;DFS1(rt,0);DFS2(rt);
  rt2=1;rep(x,2,n)if(dep[x]>dep[rt2])rt2=x;
  rep(i,1,n)Max[i][0]=Min[i][0]=max(dep[i],dis(i,rt2));
  cs=0;
  per(i,n-1,1){
   nxt[i][0]=i+1;
   for(t=1;x=nxt[i][t-1];cs=max(cs,t++)){
    nxt[i][t]=nxt[x][t-1];
    Max[i][t]=max(Max[i][t-1],Max[x][t-1]);
    Min[i][t]=min(Min[i][t-1],Min[x][t-1]);
   }
  }
  while(m--){
   read(t);
   for(x=y=1;y<=n;++x,++y){
    while(get(x,y)<=t&&y<=n)
     ++y;
   }
   printf("%d\n",y-x);
  }
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值