注意到这一点:边权非负。
首先对第一棵树进行边分治。式子变成了 D ( x ) + D ( y ) + dist2 ( x , y ) + dist3(x,y) D(x)+D(y)+\text{dist2}(x,y)+\text{dist3(x,y)} D(x)+D(y)+dist2(x,y)+dist3(x,y),显然可以对第二颗树继续分治,但是这样复杂度 O ( n log 3 n ) O(n\log^3 n) O(nlog3n)难以通过。
假设 x , y x,y x,y在第二颗树上的最近公共祖先为 p p p,我们考虑对于 x ′ x' x′与 x x x之间连一条边,权值为 D ( x ) + dep2(x) D(x)+\text{dep2(x)} D(x)+dep2(x),那么可以转化为求第三棵树上的最远点对问题。
想到了什么?没错,在一棵树上两个集合并集的最远点对是可以直接合并的。
那么直接在第二棵树的虚树上统计答案即可。
复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define db double
#define pb push_back
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N=8e5+5;
int T,n,n2;
int dep[N],dep2[N],vis[N],dfn[N],tp[N],tp2[N],fa[N],fa2[N],son[N],son2[N],siz2[N],siz3[N],num,c[N];
int hd[N],to[N],st[N],nxt[N],tot=1;
ll dis1[N],dis2[N],dis3[N],w[N],res;
vector<pair<int,ll>>g[N];
void add(int x,int y,ll z){
to[++tot]=y,w[tot]=z,st[tot]=x,nxt[tot]=hd[x],hd[x]=tot;
to[++tot]=x,w[tot]=z,st[tot]=y,nxt[tot]=hd[y],hd[y]=tot;
}
int Lca(int x,int y){
int fx=tp[x],fy=tp[y];
while(fx!=fy){
if(dep[fx]>dep[fy])x=fa[fx];
else y=fa[fy];
fx=tp[x],fy=tp[y];
}return dep[x]<dep[y]?x:y;
}
int Lca2(int x,int y){
int fx=tp2[x],fy=tp2[y];
while(fx!=fy){
if(dep2[fx]>dep2[fy])x=fa2[fx];
else y=fa2[fy];
fx=tp2[x],fy=tp2[y];
}return dep2[x]<dep2[y]?x:y;
}
void dfs(int u,int topf){
int lst=u;
for(auto v:g[u]){
if(v.fi!=topf){
n2++,add(lst,n2,0),add(n2,v.fi,v.se),lst=n2,dfs(v.fi,u);
}
}
}
void dfs2(int u,int topf){
dfn[u]=++num,fa[u]=topf,dep[u]=dep[topf]+1,siz2[u]=1;
for(auto v:g[u]){
if(v.fi!=topf){
dis2[v.fi]=dis2[u]+v.se,dfs2(v.fi,u),siz2[u]+=siz2[v.fi];
if(siz2[v.fi]>siz2[son[u]])son[u]=v.fi;
}
}
}
void dfs7(int u,int topf){
tp[u]=topf;
if(son[u])dfs7(son[u],topf);
for(auto v:g[u]){
if(!tp[v.fi])dfs7(v.fi,v.fi);
}
}
void dfs3(int u,int topf){
fa2[u]=topf,dep2[u]=dep2[topf]+1,siz3[u]=1;
for(auto v:g[u]){
if(v.fi!=topf){
dis3[v.fi]=dis3[u]+v.se,dfs3(v.fi,u),siz3[u]+=siz3[v.fi];
if(siz3[v.fi]>siz3[son2[u]])son2[u]=v.fi;
}
}
}
void dfs8(int u,int topf){
tp2[u]=topf;
if(son2[u])dfs8(son2[u],topf);
for(auto v:g[u]){
if(!tp2[v.fi])dfs8(v.fi,v.fi);
}
}
int edge,D,siz[N];
void dfs4(int u,int topf,int sz){
siz[u]=1;
for(int k=hd[u];k;k=nxt[k]){
int v=to[k];
if(!vis[k]&&v!=topf){
dfs4(v,u,sz),siz[u]+=siz[v];
if(max(siz[v],sz-siz[v])<D)D=max(siz[v],sz-siz[v]),edge=k;
}
}
}
int m,p[N],s[N],cnt;
vector<int>vec,g2[N];
void dfs5(int u,int topf,int C){
c[u]=C;if(u<=n)p[++m]=u;
for(int k=hd[u];k;k=nxt[k]){
int v=to[k];
if(!vis[k]&&v!=topf){
dis1[v]=dis1[u]+w[k],dfs5(v,u,C);
}
}
}
bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
void Add(int x,int y){
if(dep[x]>dep[y])swap(x,y);
g2[x].pb(y);
}
void build(){
for(int i=1;i<=m;i++)vec.pb(p[i]);
s[cnt=1]=1,vec.pb(1);sort(p+1,p+1+m,cmp);
for(int i=1;i<=m;i++){
if(p[i]==1)continue;
int u=p[i],v=Lca(s[cnt],u),lst=0;
if(s[cnt]==v)s[++cnt]=u;
else{
while(dep[s[cnt]]>dep[v]){
if(lst)Add(s[cnt],lst);
lst=s[cnt--];
}
if(s[cnt]==v){
Add(lst,v),s[++cnt]=u;
}
else{
Add(lst,v),s[++cnt]=v,vec.pb(v),s[++cnt]=u;
}
}
}for(int i=1;i<cnt;i++)Add(s[i],s[i+1]);
}
ll ask(int x,int y){
if(!x||!y||x==y)return -inf;
return dis3[x]+dis3[y]-2*dis3[Lca2(x,y)]+dis1[x]+dis1[y]+dis2[x]+dis2[y]+w[edge];
}
struct node{
int a,b;
bool operator <(const node &r)const{
return ask(a,b)<ask(r.a,r.b);
}
node operator +(const node &r)const{
if(!a||!r.a)return {a+r.a,b+r.b};
return max({(node){a,r.a},(node){a,r.b},(node){b,r.a},(node){b,r.b},(node){a,b},r});
}
}dp[N],dp2[N];
void dfs6(int u){
dp[u]=dp2[u]={0,0};
if(c[u]==1)dp[u]={u,u};
if(c[u]==2)dp2[u]={u,u};
for(auto v:g2[u]){
dfs6(v);
ll tmp=max({ask(dp[u].a,dp2[v].a),ask(dp[u].a,dp2[v].b),ask(dp[u].b,dp2[v].a),ask(dp[u].b,dp2[v].b)});
ll tmp2=max({ask(dp2[u].a,dp[v].a),ask(dp2[u].a,dp[v].b),ask(dp2[u].b,dp[v].a),ask(dp2[u].b,dp[v].b)});
res=max(res,max(tmp,tmp2)-2*dis2[u]);
dp[u]=dp[u]+dp[v],dp2[u]=dp2[u]+dp2[v];
}
}
void solve(int u,int sz){
if(sz==1)return;
edge=-1,D=0x3f3f3f3f;
dfs4(u,0,sz);vis[edge]=vis[edge^1]=1;
dis1[st[edge]]=dis1[to[edge]]=0,m=0,dfs5(st[edge],0,1),dfs5(to[edge],0,2);
build(),dfs6(1);
for(int i=0;i<vec.size();i++)c[vec[i]]=0,g2[vec[i]].clear();vec.clear();
int tmp=edge;
solve(st[tmp],sz-siz[to[tmp]]),solve(to[tmp],siz[to[tmp]]);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n,n2=n;
for(int i=1;i<n;i++){
int x,y;ll z;cin>>x>>y>>z;
g[x].pb({y,z}),g[y].pb({x,z});
}dfs(1,0);for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<n;i++){
int x,y;ll z;cin>>x>>y>>z;
g[x].pb({y,z}),g[y].pb({x,z});
}dfs2(1,0),dfs7(1,1);for(int i=1;i<=n;i++)g[i].clear(),son[i]=0;
for(int i=1;i<n;i++){
int x,y;ll z;cin>>x>>y>>z;
g[x].pb({y,z}),g[y].pb({x,z});
}dfs3(1,0),dfs8(1,1);for(int i=1;i<=n;i++)g[i].clear();
solve(1,n2);cout<<res;
}