题目
多组询问,在 \([a,b]\) 和 \([c,d]\) 中分别选一个点 \(x,y\) ,使得 \(dis(x,y)\) 最大
分析
考虑直径的一个性质,两个点集两条直径的四个端点可能成为合并后点集的直径,
用线段树维护区间直径询问时合并即可,LCA可以用dfs序 \(O(1)\) 询问
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=100011; struct node{int y,w,next;}e[N<<1];
struct rec{int x,y;}w[N<<2];
int dep[N],dis[N],f[N<<1][18],two[18],lg[N<<1],dfn[N],as[N],n,tot,et=1;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int max(int a,int b){return a>b?a:b;}
void dfs(int x,int fa){
dep[x]=dep[fa]+1,f[dfn[x]=++tot][0]=x;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
dis[e[i].y]=dis[x]+e[i].w;
dfs(e[i].y,x),f[++tot][0]=x;
}
}
int Get_Min(int x,int y){return dep[x]<dep[y]?x:y;}
int lca(int x,int y){
int l=dfn[x],r=dfn[y];
if (l>r) l^=r,r^=l,l^=r;
int z=lg[r-l+1];
return Get_Min(f[l][z],f[r-two[z]+1][z]);
}
int Dis(int x,int y){return dis[x]+dis[y]-2*dis[lca(x,y)];}
rec pup(rec A,rec B){
rec t=A; int d=Dis(A.x,A.y),now;
now=Dis(B.x,B.y); if (now>d) d=now,t=B;
now=Dis(A.x,B.x); if (now>d) d=now,t=(rec){A.x,B.x};
now=Dis(A.x,B.y); if (now>d) d=now,t=(rec){A.x,B.y};
now=Dis(A.y,B.x); if (now>d) d=now,t=(rec){A.y,B.x};
now=Dis(A.y,B.y); if (now>d) d=now,t=(rec){A.y,B.y};
return t;
}
void build(int k,int l,int r){
if (l==r){
w[k]=(rec){l,l};
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
rec query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
int mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
int main(){
n=iut(),lg[0]=-1,two[0]=1;
for (int i=1;i<18;++i) two[i]=two[i-1]<<1;
for (int i=1;i<n;++i){
int x=iut(),y=iut(),w=iut();
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
dfs(1,0);
for (int i=1;i<=tot;++i) lg[i]=lg[i>>1]+1;
for (int j=1;j<=lg[tot];++j)
for (int i=1;i+two[j]-1<=tot;++i)
f[i][j]=Get_Min(f[i][j-1],f[i+two[j-1]][j-1]);
build(1,1,n);
for (int Q=iut();Q;--Q,putchar(10)){
int lx=iut(),ly=iut(),rx=iut(),ry=iut(); rec tl=query(1,1,n,lx,ly),tr=query(1,1,n,rx,ry);
print(max(max(Dis(tl.x,tr.x),Dis(tl.x,tr.y)),max(Dis(tl.y,tr.x),Dis(tl.y,tr.y))));
}
return 0;
}