可以发现,如果把两个区间分别求一个直径,记录一下端点,那么最优解一定是这四个端点中的任意两个构成的,且这两个点不能来自同一个区间,用直径的性质很好证明
然后我们就可以用一个线段树维护一下下标区间的直径的端点
然后,本题卡常,要用rmq-lca才能过
Code:
#include<bits/stdc++.h>
#define ls tr[k].l
#define rs tr[k].r
#define fi first
#define se second
#define mid ((ls+rs)>>1)
#define pi pair<int,int>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5;
namespace LCA{
int vis[N<<1],nxt[N<<1],c[N<<1],head[N<<1],tot=0;
inline void add(int x,int y,int z){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;c[tot]=z;}
int d[N<<1],pt[N],dep[N],sta[N<<1],cnt=0,fipos[N];
void dfs(int v,int depp){
pt[v]=1;sta[++cnt]=v;fipos[v]=cnt;d[cnt]=depp;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(pt[y]) continue;
dep[y]=dep[v]+c[i];
dfs(y,depp+1);
sta[++cnt]=v;d[cnt]=depp;
}
}
int f[N<<1][21];
void init(){
for(int i=1;i<=cnt;i++) f[i][0]=i;
int t=log(cnt)/log(2)+1;
for(int j=1;j<t;j++)
for(int i=1;i<=cnt-(1<<j)+1;i++){
int x=f[i][j-1],y=f[i+(1<<(j-1))][j-1];
f[i][j]=(d[x]<d[y])?x:y;
}
}
inline int query(int l,int r){
int t=log(r-l+1)/log(2);
int x=f[l][t],y=f[r-(1<<t)+1][t];
return (d[x]<d[y])?x:y;
}
inline int lca(int x,int y){int l=fipos[x],r=fipos[y];if(l>r) swap(l,r);return sta[query(l,r)];}
inline int ask(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
}
using namespace LCA;
namespace segtree{
struct seg{int l,r,u,v;}tr[N<<1];
inline void pushup(int k){
int u[5];u[1]=tr[k<<1].u,u[2]=tr[k<<1|1].u;
u[3]=tr[k<<1].v,u[4]=tr[k<<1|1].v;
int maxn=0;
for(int i=1;i<=4;i++)
for(int j=i+1;j<=4;j++){
if(u[i]==-1 || u[j]==-1) continue;
int dis=dep[u[i]]+dep[u[j]]-2*dep[lca(u[i],u[j])];
if(dis>maxn) maxn=dis,tr[k].u=u[i],tr[k].v=u[j];
}
}
inline pi merge(pi a,pi b){
pi ret;
int u[5];u[1]=a.fi,u[2]=b.fi;u[3]=a.se,u[4]=b.se;
int maxn=0;
for(int i=1;i<=4;i++)
for(int j=i+1;j<=4;j++){
if(u[i]==-1 || u[j]==-1) continue;
int dis=dep[u[i]]+dep[u[j]]-2*dep[lca(u[i],u[j])];
if(dis>maxn) maxn=dis,ret=make_pair(u[i],u[j]);
}
return ret;
}
void build(int k,int l,int r){
ls=l,rs=r;
if(l==r) {tr[k].u=l;tr[k].v=l;return;}
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
pi query(int k,int ql,int qr){
if(rs<ql || ls>qr) return make_pair(-1,-1);
if(ql<=ls && rs<=qr) return make_pair(tr[k].u,tr[k].v);
if(qr<=mid) return query(k<<1,ql,qr);
else if(ql>mid) return query(k<<1|1,ql,qr);
else return merge(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr));
}
}
using namespace segtree;
int main(){
int n=read();
for(int x,y,z,i=1;i<n;i++){x=read(),y=read(),z=read();add(x,y,z);add(y,x,z);}
dfs(1,0);init();
build(1,1,n);
int m=read();
int a,b,c,d;
while(m--){
a=read(),b=read(),c=read(),d=read();
pi t1=query(1,a,b);
pi t2=query(1,c,d);
cout<<max(max(ask(t1.first,t2.first),ask(t1.first,t2.second)),max(ask(t1.second,t2.first),ask(t1.second,t2.second)))<<"\n";
}
return 0;
}