正解:对于每个询问以a~b,c~d之间的点为关键点建虚树,然后枚举a到b中的每一个点,bfs求最长路即可
原题中存在区间询问,因此八成会扯到数据结构,尤其是线段树。
然而……线段树维护区间最长路?
首先我们有这样一个结论:
对于两棵树,设它们的直径/最长路分别为
(a,b)
(
a
,
b
)
和
(c,d)
(
c
,
d
)
,
则两棵树合并成新树后,最长路的端点也必然在
a,b,c,d
a
,
b
,
c
,
d
四个点之中。计算的时候枚举四个点中的任意两个,求树上距离就可以了。
利用这样一个结论,我们就可以合并区间的答案,于是我们就可以用线段树来维护区间的最长路了。
此外还有一个小问题,鉴于本方法要算如此多次LCA,明显应该使用ST表这类O(1)的算法,否则怕是得TLE上天。
事实上上面那个结论非常好用,可以很容易求出任意点集的最远点对等等,由此衍生出了一系列极其玄妙的题,如JZOJ4587(Snow的追寻)以及并查集+树的直径之类的东西。
具体实现见代码如下:
#include <bits/stdc++.h>
using namespace std;
int read()
{
int X=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')X=X*10+ch-'0',ch=getchar();
return X;
}
struct edge
{
int v,l,p;
}e[200100];
struct node
{
int u,v;
}t[400000];
int n,m,head[100010],top,dfs_clock,st[20][300000],d[100010],dfn[300010],lg2[300010],pl[100010];
void addedge(int u,int v,int l)
{
e[++top]=(edge){v,l,head[u]};
head[u]=top;
e[++top]=(edge){u,l,head[v]};
head[v]=top;
}
void dfs(int u,int fa)
{
dfn[++dfs_clock]=u;
pl[u]=dfs_clock;
for(int i=head[u];i;i=e[i].p)
{
int v=e[i].v;
if(v==fa)continue;
d[v]=d[u]+e[i].l;
dfs(v,u);
dfn[++dfs_clock]=u;
}
}
void build_st()
{
for(int i=1,j=-1;i<=dfs_clock;i++)
{
if(i==(i&-i))j++;
lg2[i]=j;
st[0][i]=d[dfn[i]];
// cout<<d[dfn[i]]<<' ';
}
// cout<<endl;
for(int i=1;i<=lg2[dfs_clock];i++)
{
for(int j=1;j<=dfs_clock-(1<<(i-1));j++)
{
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
}
}
inline int dist(int u,int v)
{
if(u==v)return 0;
if(pl[u]>pl[v])swap(u,v);
int temp=lg2[pl[v]-pl[u]+1];
// cout<<"----------------"<<u<<' '<<v<<' '<<d[u]<<' '<<d[v]<<' '<<temp<<' '<<pl[u]<<' '<<pl[v]<<' '<<st[temp][pl[u]]<<' '<<st[temp][pl[v]-(1<<temp)+1]<<' '<<min(st[temp][pl[u]],st[temp][pl[v]-(1<<temp)+1])<<endl;
return d[u]+d[v]-2*min(st[temp][pl[u]],st[temp][pl[v]-(1<<temp)+1]);
}
void merge(int u1,int v1,int u2,int v2,int &ans1,int &ans2,bool b=0)
{
if((u1==0&&v1==0)||(u2==0&&v2==0))
{
ans1=u1+u2;
ans2=v1+v2;
return;
}
int ret=0,dd[6]={dist(u1,u2),dist(u1,v2),dist(v1,u2),dist(v1,v2),dist(u1,v1),dist(u2,v2)};
int ee[6][2]={{u1,u2},{u1,v2},{v1,u2},{v1,v2},{u1,v1},{u2,v2}};
for(int i=0;i<(b?4:6);i++)
{
ret=max(dd[i],ret);
if(ret==dd[i])ans1=ee[i][0],ans2=ee[i][1];
}
}
void build(int k,int l,int r)
{
if(l==r)
{
t[k]=(node){l,r};
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
merge(t[k<<1].u,t[k<<1].v,t[k<<1|1].u,t[k<<1|1].v,t[k].u,t[k].v);
// cout<<"-------------"<<k<<' '<<l<<' '<<r<<' '<<t[k].u<<' '<<t[k].v<<endl;
}
void ask(int k,int l,int r,int L,int R,int &ans1,int &ans2)
{
if(L<=l&&r<=R)
{
ans1=t[k].u;
ans2=t[k].v;
return;
}
int mid=(l+r)>>1,u1=0,v1=0,u2=0,v2=0;
if(L<=mid)ask(k<<1,l,mid,L,R,u1,v1);
if(R>mid)ask(k<<1|1,mid+1,r,L,R,u2,v2);
merge(u1,v1,u2,v2,ans1,ans2);
// cout<<k<<' '<<l<<' '<<r<<' '<<L<<' '<<R<<' '<<ans1<<' '<<ans2<<endl;
}
int query(int l1,int r1,int l2,int r2)
{
int u1,v1,u2,v2,w1,w2;
ask(1,1,n,l1,r1,u1,v1);
ask(1,1,n,l2,r2,u2,v2);
merge(u1,v1,u2,v2,w1,w2,1);
return dist(w1,w2);
}
int main()
{
cin>>n;
for(int i=1;i<n;i++)
{
int u=read(),v=read(),l=read();
addedge(u,v,l);
}
dfs(1,0);
build_st();
build(1,1,n);
cin>>m;
for(int i=1;i<=m;i++)
{
int A=read(),B=read(),C=read(),D=read();
cout<<query(A,B,C,D)<<endl;
}
return 0;
}