思路:考虑st表的思想。设
s
t
[
i
]
[
j
]
st[i][j]
st[i][j]表示
[
i
,
i
+
2
j
]
[i,i+2^j]
[i,i+2j]区间的点 构成的的树的直径的两个端点。转移就是从4个点选两个。就可以预处理出st数组。询问就是合并两个st的元素。
算是一类树上问题的技巧吧。学习到了。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int n,q;
vector<pair<int,int>>v[N];
int siz[N], fa[N], de[N], to[N], a[N], son[N];
int cnt;
LL s[N];
void dfs1(int now, int pre, int d) {
siz[now] = 1;
fa[now] = pre;
de[now] = d;
int cnt = -1;
for (auto k : v[now]) {
if (k.fi == pre)continue;
s[k.fi]=s[now]+k.se;
dfs1(k.fi, now, d + 1);
siz[now] += siz[k.fi];
if (siz[k.fi] > cnt) {
cnt = siz[k.fi];
son[now] = k.fi;
}
}
}
void dfs2(int now, int pre) {
to[now] = pre;
a[now] = ++cnt;
if (!son[now])return ;
dfs2(son[now], pre);
for (auto k : v[now]) {
if (k.fi == fa[now] || k.fi == son[now])continue;
dfs2(k.fi, k.fi);
}
}
int find_lca(int l, int r) {
// cout<<l<<' '<<r<<' ';
while (to[l] != to[r]) {
if (de[to[l]] < de[to[r]])swap(l, r);
l = fa[to[l]];
}
if (de[l] > de[r])swap(l, r);
// cout<<l<<endl;
return l;
}
LL dis(int x,int y){
return s[x]+s[y]-2*s[find_lca(x,y)];
}
pair<int,int> st[N][22];
int lg[N];
void gao() {
lg[0] = -1;
for (int i = 1; i < N; i++)
lg[i] = lg[i >> 1] + 1;
for(int i=1;i<=n;i++)st[i][0]={i,i};
for (int j = 1; j < 20; j++) {
for (int i = 1; i +(1<<j)-1<= n; i++) {
// st[i][0] = {i, i + 1}; //表示 [i,i+2^x] 区间 直径的两个端点
// cout<<i<<endl;
// cout << i << ' ' << (i + (1 << j)) << endl;
auto l = st[i][j - 1], r = st[i + (1 << j - 1)][j - 1];
auto z = l;
LL now=dis(l.fi,l.se);
LL pre;
if((pre=dis(r.fi,r.se))>now)z=r,now=pre;
if(now<(pre=dis(l.fi,r.fi)))z={l.fi,r.fi},now=pre;
if(now<(pre=dis(l.fi,r.se)))z={l.fi,r.se},now=pre;
if(now<(pre=dis(r.fi,l.se)))z={r.fi,l.se},now=pre;
if(now<(pre=dis(r.se,l.se)))z={r.se,l.se},now=pre;
st[i][j] = z;
}
}
}
pair<int,int>merge(pair<int,int>l,pair<int,int>r){
auto z=l;
// cout<<l.fi<<' '<<l.se<<' '<<r.fi<<' '<<r.se<<endl;
LL now=dis(l.fi,l.se);
LL pre;
if((pre=dis(r.fi,r.se))>now)z=r,now=pre;
if(now<(pre=dis(l.fi,r.fi)))z={l.fi,r.fi},now=pre;
if(now<(pre=dis(l.fi,r.se)))z={l.fi,r.se},now=pre;
if(now<(pre=dis(r.fi,l.se)))z={r.fi,l.se},now=pre;
if(now<(pre=dis(r.se,l.se)))z={r.se,l.se},now=pre;
return z;
}
int main() {
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
int s,t,w;
scanf("%d%d%d",&s,&t,&w);
v[s].emplace_back(t,w);
v[t].emplace_back(s,w);
}
//dis l r =d_l +d_r -2d_lca
dfs1(1,0,0);
dfs2(1,1);
gao();
for(int i=1;i<=q;i++){
int l,r;
scanf("%d%d",&l,&r);
int k=lg[r-l+1];
auto x=merge(st[l][k],st[r-(1<<k)+1][k]);
printf("%lld\n",dis(x.fi,x.se));
// cout<<find_lca(x.fi,x.se)<<endl;
}
return 0;
}