题目大意:
n个点被n-1条边连接成了一颗树,给出ab和cd两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}
(PS 建议使用读入优化)
思路:
首先必须要知道一个结论:若集合A中的点的最远点对为(a,b),集合B中的最远点对为(c,d),那么集合AUB中的最远点对必定是a,b,c,d四个点组成的。
证明反证法即可。
于是直接用线段树维护编号连续区间的最远点对,查询直接暴力pushup。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("51nod1766.in","r",stdin);
freopen("51nod1766.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=1e5+10;
int n,q;
int beg[maxn],las[maxn<<1],to[maxn<<1],w[maxn<<1],cnte=1;
int st[maxn<<1][22],dep[maxn],Log[maxn<<1],cnt,pos[maxn];
void add(int u,int v,int val){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; w[cnte]=val;
}
void dfs(int u,int f,int d){
st[++cnt][0]=u;
dep[u]=d; pos[u]=cnt;
for(int i=beg[u];i;i=las[i]){
if(to[i]==f)continue;
dfs(to[i],u,d+w[i]);
st[++cnt][0]=u;
}
}
int rmq(int l,int r){
int k=Log[r-l+1],len=1<<k;
return dep[st[l][k]]<dep[st[r-len+1][k]] ? st[l][k] : st[r-len+1][k];
}
int lca(int x,int y){
x=pos[x]; y=pos[y];
if(x>y)swap(x,y);
return rmq(x,y);
}
int dis(int x,int y){
int an=lca(x,y);
return dep[x]+dep[y]-dep[an]*2;
}
struct node{
int s,t;
node operator + (const node & tt) const {
node r[7]; int d[7],Max=0;
r[1]=(node){s,t}; d[1]=dis(r[1].s,r[1].t);
r[2]=(node){s,tt.s}; d[2]=dis(r[2].s,r[2].t);
r[3]=(node){s,tt.t}; d[3]=dis(r[3].s,r[3].t);
r[4]=(node){t,tt.s}; d[4]=dis(r[4].s,r[4].t);
r[5]=(node){t,tt.t}; d[5]=dis(r[5].s,r[5].t);
r[6]=(node){tt.s,tt.t}; d[6]=dis(r[6].s,r[6].t);
REP(i,1,6)Max=max(Max,d[i]);
REP(i,1,6)if(d[i]==Max)return r[i];
}
node operator * (const node & tt) const {
node r[7]={0}; int d[7]={0},Max=0;
r[2]=(node){s,tt.s}; d[2]=dis(r[2].s,r[2].t);
r[3]=(node){s,tt.t}; d[3]=dis(r[3].s,r[3].t);
r[4]=(node){t,tt.s}; d[4]=dis(r[4].s,r[4].t);
r[5]=(node){t,tt.t}; d[5]=dis(r[5].s,r[5].t);
REP(i,1,6)Max=max(Max,d[i]);
REP(i,1,6)if(d[i]==Max)return r[i];
}
};
struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
node path[maxn<<2];
void build(int rt,int l,int r){
if(l==r)path[rt]=(node){l,l};
else{
build(lson); build(rson);
path[rt]=path[lc]+path[rc];
}
}
node query(int rt,int l,int r,int L,int R){
if(L<=l && r<=R)return path[rt];
if(L<=mid && R>=mid+1)return query(lson,L,R)+query(rson,L,R);
if(L<=mid)return query(lson,L,R);
return query(rson,L,R);
}
}T;
void init(){
read(n);
int u,v,val;
REP(i,1,n-1)read(u),read(v),read(val),add(u,v,val);
REP(i,2,maxn*2-10)Log[i]=Log[i/2]+1;
dfs(1,0,0);
REP(j,1,Log[cnt]){
int len=1<<j;
REP(i,1,cnt-len+1)
st[i][j]= dep[st[i][j-1]]<dep[st[i+len/2][j-1]] ? st[i][j-1] : st[i+len/2][j-1];
}
}
void work(){
T.build(1,1,n);
read(q);
int a,b,c,d;
REP(i,1,q){
read(a); read(b); read(c); read(d);
node ans=T.query(1,1,n,a,b)*T.query(1,1,n,c,d);
int di=dis(ans.s,ans.t);
printf("%d\n",di);
}
}
int main(){
File();
init();
work();
return 0;
}