我不知道题解应该叫什么名字
处理每一个节点的复苏情况是简单的。
因此我们可以使用倍增数组实现一个数组 dea[x][i],代表从
因此,我们可以使用
对于每一次查询,我们如下考虑:
最简单的方法肯定是从
因此,我们考虑移动到
也就是说,我们定义
那么,我们要处理的代价为
前两个已经可以使用刚才的倍增解决了,所以我们只需要思考如何处理
因为两端都已经不足
以下是代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,M=4e5+5;
int ver[M],ne[M],w[M],head[N],tot;
int lc[N][30],dea[N][30],dep[N],sum[N];
int n,k;
inline int read(){
int s=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s;
}
inline void add(int x,int y,int z){
ver[++tot]=y,w[tot]=z;
ne[tot]=head[x],head[x]=tot;
}
inline int get(int x){//x复苏一次能到达的位置
int tmp=x;
for(int i=20;i>=0;i--) if(sum[x]-sum[lc[tmp][i]]<k) tmp=lc[tmp][i];//还可以跳就往上跳
return lc[tmp][0];//跳上去后复苏
}
inline void dfs(int x,int fa){
dep[x]=dep[fa]+1,lc[x][0]=fa;
for(int i=1;i<=20;i++) lc[x][i]=lc[lc[x][i-1]][i-1];
dea[x][0]=get(x);
for(int i=1;i<=20;i++) dea[x][i]=dea[dea[x][i-1]][i-1];
for(int i=head[x];i;i=ne[i]){
int y=ver[i];
if(y==fa) continue;
sum[y]=sum[x]+w[i];
dfs(y,x);
}
}
inline int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--)
if(dep[lc[x][i]]>=dep[y]) x=lc[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
if(lc[x][i]!=lc[y][i]) x=lc[x][i],y=lc[y][i];
return lc[x][0];
}
signed main(){
cin>>n>>k;
for(int i=1;i<n;i++){
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
dfs(1,0);
int T;cin>>T;
while(T--){
int x=read(),y=read();
int z=lca(x,y);
int ans=0;
for(int i=20;i>=0;i--)
if(dep[dea[x][i]]>=dep[z]) x=dea[x][i],ans+=(1<<i);//x 跳上去
for(int i=20;i>=0;i--)
if(dep[dea[y][i]]>=dep[z]) y=dea[y][i],ans+=(1<<i);//y 跳上去
cout<<ans+((sum[x]+sum[y]-2*sum[z]>=k)?1:0)<<"\n";//两端不会再有,所以只需要检查中间是否需要
}
return 0;
}