锟题x1
以下用$d_k(x,y)$表示$x,y$在第树$k$上的距离,$h_k(x)$表示$x$在树$k$上的深度
先做两棵树,即最大化$d_1(x,y)+d_2(x,y)=h_1(x)+h_1(y)-2h_1(lca)+d_2(x,y)$,其中$lca$是$x,y$在树$1$上的lca
考虑在树$1$上枚举$lca$,即是要最大化$h_1(x)+h_2(y)+d_2(x,y)$,于是我们可以对每个树$2$的点$i$建多一条边$(i,i',h_1(i))$,在dfs树$1$的同时维护(树$1$的子树中的每个$x$对应到树$2$的$x'$这些点在树$2$中的直径)即可
现在有了树$3$,考虑对其边分治,设分治到$(u,v)$,我们要查询在树$3$上跨过$(u,v)$的答案,这其实就是在两棵树的基础上加了$d_3(x,u)+d_3(y,v)+w_{u,v}$还有路径$(x,y)$必须经过$(u,v)$的约束,那么将当前分治范围内的点拿出来在树$1$上建虚树,并给$(u,v)$两边的点染不同的颜色,于是接下来我们维护不同颜色的直径,之后就和两棵树完全一样了
最后的一个小问题就是边分治的复杂度,这里直接多叉转二叉即可(对每个点新建一条$0$链)
说起来很简单,但写起来还是挺长的
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<assert.h>
using namespace std;
typedef long long ll;
const int inf=2147483647;
int n;
struct tree1{
int h[100010],nex[200010],to[200010],M;
ll v[200010];
void add(int a,int b,ll c){
M++;
to[M]=b;
v[M]=c;
nex[M]=h[a];
h[a]=M;
}
int fa[100010],dfn[100010],mn[200010][18],dep[200010],lg[200010];
ll d[100010];
void dfs(int x){
dfn[x]=++M;
mn[M][0]=x;
dep[x]=dep[fa[x]]+1;
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x]){
fa[to[i]]=x;
d[to[i]]=d[x]+v[i];
dfs(to[i]);
mn[++M][0]=x;
}
}
}
int qmin(int x,int y){return dep[x]<dep[y]?x:y;}
int query(int l,int r){
int k=lg[r-l+1];
return qmin(mn[l][k],mn[r-(1<<k)+1][k]);
}
int lca(int x,int y){
if(dfn[x]>dfn[y])swap(x,y);
return query(dfn[x],dfn[y]);
}
void gao(){
int i,j,x,y;
ll z;
for(i=1;i<n;i++){
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
M=0;
dfs(1);
for(j=1;j<18;j++){
for(i=1;i+(1<<j)-1<=M;i++)mn[i][j]=qmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
for(i=2;i<=M;i++)lg[i]=lg[i>>1]+1;
}
}t1;
struct tree2{
int h[100010],nex[200010],to[200010],M;
ll v[200010];
void add(int a,int b,ll c){
M++;
to[M]=b;
v[M]=c;
nex[M]=h[a];
h[a]=M;
}
int fa[100010],lg[200010],in[100010];
ll d[100010],mn[200010][19];
void dfs(int x){
in[x]=++M;
mn[M][0]=d[x];
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x]){
fa[to[i]]=x;
d[to[i]]=d[x]+v[i];
dfs(to[i]);
mn[++M][0]=d[x];
}
}
}
ll query(int l,int r){
int k=lg[r-l+1];
return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
ll dis(int x,int y){
if(in[x]>in[y])swap(x,y);
return d[x]+d[y]-2*query(in[x],in[y]);
}
void gao(){
int i,j,x,y;
ll z;
for(i=1;i<n;i++){
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
M=0;
dfs(1);
for(j=1;j<19;j++){
for(i=1;i+(1<<j)-1<=M;i++)mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
for(i=2;i<=M;i++)lg[i]=lg[i>>1]+1;
}
}t2;
struct pr{
int to;
ll v;
pr(int a=0,ll b=0){to=a;v=b;}
};
struct tree3{
int h[200010],nex[400010],to[400010],M;
ll v[400010];
void ins(int a,int b,ll c){
M++;
to[M]=b;
v[M]=c;
nex[M]=h[a];
h[a]=M;
}
void add(int a,int b,ll c){
ins(a,b,c);
ins(b,a,c);
}
vector<pr>g[100010];
int N;
void dfs(int fa,int x){
int p;
vector<pr>::iterator it;
if(g[x].size()){
p=0;
for(it=g[x].begin();it!=g[x].end();it++){
if(it->to!=fa){
if(p){
N++;
add(p,N,0);
add(N,it->to,it->v);
p=N;
}else{
add(x,it->to,it->v);
p=x;
}
}
}
}
for(it=g[x].begin();it!=g[x].end();it++){
if(it->to!=fa)dfs(x,it->to);
}
}
void gao(){
int i,x,y;
ll z;
for(i=1;i<n;i++){
scanf("%d%d%lld",&x,&y,&z);
g[x].push_back(pr(y,z));
g[y].push_back(pr(x,z));
}
N=n;
M=1;
dfs(0,1);
}
}t3;
ll dis[200010],ad;
ll get(int x,int y){
return t2.dis(x,y)+t1.d[x]+t1.d[y]+dis[x]+dis[y]+ad;
}
struct dia{
int x,y;
dia(int a=0,int b=0){x=a;y=b;}
};
ll max(dia a,dia b){
if(a.x==0||b.x==0)return 0;
return max(max(get(a.x,b.x),get(a.x,b.y)),max(get(a.y,b.x),get(a.y,b.y)));
}
dia operator+(dia a,dia b){
if(a.x==0)return b;
if(b.x==0)return a;
int x,y;
ll mx=0,t;
#define ch(u,v) t=get(u,v);\
if(t>mx){\
x=u;\
y=v;\
mx=t;\
}
ch(a.x,a.y)
ch(b.x,b.y)
ch(a.x,b.x)
ch(a.x,b.y)
ch(a.y,b.x)
ch(a.y,b.y)
return dia(x,y);
}
struct pd{
dia x,y;
pd(dia a=0,dia b=0){x=a;y=b;}
dia&operator[](int k){return k?x:y;}
};
pd operator+(pd a,pd b){return pd(a.x+b.x,a.y+b.y);}
ll max(pd a,pd b){return max(max(a.x,b.y),max(a.y,b.x));}
ll ans;
bool vis[400010];
int siz[200010],p[200010],M;
void dfs1(int fa,int x){
if(x<=n)p[++M]=x;
siz[x]=1;
for(int i=t3.h[x];i;i=t3.nex[i]){
if(!vis[i]&&t3.to[i]!=fa){
dfs1(x,t3.to[i]);
siz[x]+=siz[t3.to[i]];
}
}
}
int al,mn,cn;
void dfs2(int fa,int x){
for(int i=t3.h[x];i;i=t3.nex[i]){
if(!vis[i]&&t3.to[i]!=fa){
dfs2(x,t3.to[i]);
if(abs(al-2*siz[t3.to[i]])<mn){
mn=abs(al-2*siz[t3.to[i]]);
cn=i;
}
}
}
}
struct vtree{
int h[100010],nex[100010],to[100010],M;
void add(int a,int b){
M++;
to[M]=b;
nex[M]=h[a];
h[a]=M;
}
int col[100010];
pd dfs(int x){
pd d,t;
d[col[x]]=dia(x,x);
for(int i=h[x];i;i=nex[i]){
t=dfs(to[i]);
ans=max(ans,max(d,t)-2*t1.d[x]);
d=d+t;
}
h[x]=0;
return d;
}
}vt;
bool cmp(int x,int y){return t1.dfn[x]<t1.dfn[y];}
int st[100010],tp;
void insert(int x){
if(!tp){
st[++tp]=x;
return;
}
int l=t1.lca(x,st[tp]);
while(tp>1&&t1.dep[st[tp-1]]>t1.dep[l]){
vt.add(st[tp-1],st[tp]);
tp--;
}
if(t1.dep[st[tp]]>t1.dep[l]){
vt.add(l,st[tp]);
tp--;
}
if(t1.dep[st[tp]]<t1.dep[l])st[++tp]=l;
st[++tp]=x;
}
void build(){
int i;
sort(p+1,p+M+1,cmp);
tp=0;
for(i=1;i<=M;i++)insert(p[i]);
for(i=1;i<tp;i++)vt.add(st[i],st[i+1]);
if(st[1]!=1)vt.add(1,st[1]);
}
void dfs3(int fa,int x,int f){
if(x<=n)vt.col[x]=f;
for(int i=t3.h[x];i;i=t3.nex[i]){
if(!vis[i]&&t3.to[i]!=fa){
dis[t3.to[i]]=dis[x]+t3.v[i];
dfs3(x,t3.to[i],f);
}
}
}
void solve(int x){
int y;
M=0;
dfs1(0,x);
al=siz[x];
mn=inf;
cn=0;
dfs2(0,x);
if(cn==0)return;
vis[cn]=vis[cn^1]=1;
x=t3.to[cn];
y=t3.to[cn^1];
build();
dis[x]=dis[y]=0;
dfs3(0,x,0);
dfs3(0,y,1);
ad=t3.v[cn];
vt.dfs(1);
vt.M=0;
solve(x);
solve(y);
}
int main(){
scanf("%d",&n);
t1.gao();
t2.gao();
t3.gao();
solve(1);
printf("%lld",ans);
}