题目大意
一颗边权树,给你若干点对(ai,bi)。
找到两对点对i和j,使得dis(ai,aj)+dis(bi,bj)最大。
做法
先建立点分树。
然后进行点分,对于当前分治中心x,讨论最终点对中两个a路径是否过x。
不过x,递归处理。
过x,求出当前分治联通块每个点到x的距离,然后接下来按一个一个子树处理(一起询问,再一起插入,来保证不在同一个子树),我们把b插入到点分树中,对于点分树一个分治中心y,处理出dis(a,x)+dis(b,y)的最大值、最大值来自哪个子树以及不来自同一个子树的次大值,即可完成询问。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
const ll inf=10000000000000000;
int h[maxn],go[maxn*2],dis[maxn*2],nxt[maxn*2],a[maxn];
int ask[maxn][2],h2[maxn],g2[maxn],n2[maxn],size[maxn];
int belong[maxn][25],son[maxn][25],mxf[maxn];
int sta[maxn];
ll d[maxn],dep[maxn][25],mx[maxn],se[maxn];
bool bz[maxn],pd[maxn];
int i,j,k,l,t,n,m,top,tot,cnt;
ll ans;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=z;
nxt[tot]=h[x];
h[x]=tot;
}
void add2(int x,int y){
g2[++tot]=y;
n2[tot]=h2[x];
h2[x]=tot;
}
void travel(int x,int y){
a[++top]=x;
size[x]=1;
int t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y){
travel(go[t],x);
size[x]+=size[go[t]];
}
t=nxt[t];
}
}
void dg(int x,int y,int d,int c){
son[x][d]=c;
int t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y){
dep[go[t]][d]=dep[x][d]+(ll)dis[t];
dg(go[t],x,d,c);
}
t=nxt[t];
}
}
void build(int x,int y){
top=0;
travel(x,0);
int i,t,j=x,k=0;
while (1){
t=h[j];
while (t){
if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){
k=j;
j=go[t];
break;
}
t=nxt[t];
}
if (!t) break;
}
fo(i,1,top) belong[a[i]][y]=j;
t=h[j];
while (t){
if (!bz[go[t]]){
dep[go[t]][y]=dis[t];
dg(go[t],j,y,go[t]);
}
t=nxt[t];
}
son[j][y]=j;
bz[j]=1;
t=h[j];
while (t){
if (!bz[go[t]]) build(go[t],y+1);
t=nxt[t];
}
}
void change(int x,ll v){
int j;
int y;
ll w;
fo(j,0,25){
y=belong[x][j];
if (!pd[y]){
pd[y]=1;
sta[++cnt]=y;
}
w=v+dep[x][j];
if (mxf[y]==son[x][j]) mx[y]=max(mx[y],w);
else if (w>=mx[y]){
se[y]=mx[y];
mx[y]=w;
mxf[y]=son[x][j];
}
else if (w>=se[y]) se[y]=w;
if (x==y) break;
}
}
void query(int x,ll v){
int j;
int y;
ll w;
fo(j,0,25){
y=belong[x][j];
if (mx[y]==-inf) return;
w=v+dep[x][j];
if (mxf[y]==son[x][j]) ans=max(ans,w+se[y]);
else ans=max(ans,w+mx[y]);
if (x==y) break;
}
}
void cx(int x,int y,int d){
int t=h2[x];
while (t){
query(g2[t],dep[x][d]);
t=n2[t];
}
t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y) cx(go[t],x,d);
t=nxt[t];
}
}
void cr(int x,int y,int d){
int t=h2[x];
while (t){
change(g2[t],dep[x][d]);
t=n2[t];
}
t=h[x];
while (t){
if (!bz[go[t]]&&go[t]!=y) cr(go[t],x,d);
t=nxt[t];
}
}
void solve(int x,int y){
int j=belong[x][y];
cnt=0;
int t=h2[j];
while (t){
query(g2[t],0);
change(g2[t],0);
t=n2[t];
}
t=h[j];
while (t){
if (!bz[go[t]]){
cx(go[t],j,y);
cr(go[t],j,y);
}
t=nxt[t];
}
int i;
fo(i,1,cnt){
pd[sta[i]]=0;
mx[sta[i]]=se[sta[i]]=-inf;
mxf[sta[i]]=0;
}
bz[j]=1;
t=h[j];
while (t){
if (!bz[go[t]]) solve(go[t],y+1);
t=nxt[t];
}
}
int main(){
n=read();m=read();
fo(i,1,n-1){
j=read();k=read();l=read();
add(j,k,l);add(k,j,l);
}
tot=0;
fo(i,1,m){
ask[i][0]=read();ask[i][1]=read();
add2(ask[i][0],ask[i][1]);
}
build(1,0);
fo(i,1,n) mx[i]=se[i]=-inf;
fo(i,1,n) bz[i]=0;
solve(1,0);
printf("%lld\n",ans);
}