考场打了树分治套链分治拿了64分…
大概就是把第三棵树树分治,(用左儿子右兄弟的方法重构),然后在第二棵树建立虚树,然后树形DP,每个点记录子树的点在第一棵树中距离最大的两个点,然后合并
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <assert.h>
#define show(x) cout<<'\t'<<#x<<' '<<x<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=100010;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void read(ll &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
struct edge{
int t,nx; ll w;
};
int n,lg2[N<<1];
struct tree{
int G[N],lst[N<<1],p[N],dpt[N],t,cnt;
ll cst[N];
edge E[N<<1];
int st[N<<1][20];
void dfs(int x,int f){
lst[++t]=x; p[x]=t; dpt[x]=dpt[f]+1;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f){
cst[E[i].t]=cst[x]+E[i].w;
dfs(E[i].t,x);
lst[++t]=x;
}
}
void Pre(){
int n=lg2[t];
for(int i=1;i<=t;i++) st[i][0]=lst[i];
for(int k=1;k<=n;k++)
for(int i=1;i+(1<<k)-1<=t;i++)
st[i][k]=dpt[st[i][k-1]]<dpt[st[i+(1<<k-1)][k-1]]?st[i][k-1]:st[i+(1<<k-1)][k-1];
}
inline void addedge(int x,int y,ll w){
E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].w=w; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].w=w; G[y]=cnt;
}
inline int Query(int x,int y){
x=p[x]; y=p[y];
if(x>y) swap(x,y);
int t=lg2[y-x+1];
return dpt[st[x][t]]<dpt[st[y-(1<<t)+1][t]]?st[x][t]:st[y-(1<<t)+1][t];
}
inline ll dis(int x,int y){
if(!x || !y) return -1;
return cst[x]+cst[y]-2*cst[Query(x,y)];
}
}T[3];
int G[N],cnt;
struct iedge{
int t,nx; int d;
}E[N<<1];
inline void addedge(int x,int y,int d){
//show(x); show(y);
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; E[cnt].d=d;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt; E[cnt].d=1;
}
ll df[N];
void dfs(int *G,edge *E,int x,int f){
int ad=0,lst=0;
for(int i=G[x];i;i=E[i].nx){
if(E[i].t==f) continue;
df[E[i].t]=E[i].w;
if(!ad) addedge(x,E[i].t,0),ad=1;
if(lst) addedge(lst,E[i].t,1); lst=E[i].t;
dfs(G,E,E[i].t,x);
}
}
int vis[N],size[N],isz,imax,root;
int *p=T[1].p;
void expl(int x,int f){
size[x]=1;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f && !vis[E[i].t]){
expl(E[i].t,x);
size[x]+=size[E[i].t];
}
}
void getroot(int x,int f){
int imin=0,c=0;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f && !vis[E[i].t]){
getroot(E[i].t,x);
imin=max(imin,size[E[i].t]);
c+=size[E[i].t];
}
imin=max(imin,isz-c);
if(imin<imax) imax=imin,root=x;
}
ll ans;
namespace IT{
int G[N],tp[N],cnt,S[N],vis[N],clk,t,root;
ll cst[N];
edge E[N<<1];
tree *T=::T+1;
inline bool cmp(const int &x,const int &y){
return p[x]<p[y];
}
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
void build(int *Q,int n){
T=::T+1;
cnt=0; int nt=n; ++clk;
for(int i=1;i<=n;i++)
cst[Q[i]]+=T->cst[Q[i]],vis[Q[i]]=clk;
sort(Q+1,Q+1+n,cmp);
for(int i=1;i<nt;i++){
Q[++n]=T->Query(Q[i],Q[i+1]);
if(vis[Q[n]]!=clk) tp[Q[n]]=0;
}
sort(Q+1,Q+1+n,cmp); n=unique(Q+1,Q+1+n)-Q-1; t=0;
for(int i=1;i<=n;i++){
G[Q[i]]=0;
while(t && T->Query(S[t],Q[i])!=S[t]) t--;
if(!t) root=Q[i];
else addedge(S[t],Q[i]);
S[++t]=Q[i];
}
}
int ver[N][4][2],dver[N][4][2];
inline ll calc(int *a,int *b){
//show(a[0]); show(a[1]); show(b[0]); show(b[1]); cout<<endl;
ll ret=0;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
if(a[i] && b[j]) ret=max(ret,T->dis(a[i],b[j])+cst[a[i]]+cst[b[j]]);;
return ret;
}
inline void merge(int *a,int *b){
ll cur=T->dis(a[0],a[1])+cst[a[0]]+cst[a[1]];
int x=a[0],y=a[1];
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
if(T->dis(a[i],b[j])+cst[a[i]]+cst[b[j]]>cur)
cur=T->dis(a[i],b[j])+cst[a[i]]+cst[b[j]],x=a[i],y=b[j];
}
if(T->dis(b[0],b[1])+cst[b[0]]+cst[b[1]]>cur) x=b[0],y=b[1];
a[0]=x; a[1]=y;
}
ll *dcst=::T[1].cst;
void dfs(int x,int f){
for(int i=1;i<=3;i++)
ver[x][i][0]=ver[x][i][1]=dver[x][i][0]=dver[x][i][1]=0;
if(tp[x]){
for(int i=1;i<=3;i++){
if(i==tp[x])
ver[x][i][0]=ver[x][i][1]=x;
else
dver[x][i][0]=dver[x][i][1]=x;
}
}
for(int k=G[x];k;k=E[k].nx){
int v=E[k].t;
if(v==f) continue;
dfs(v,x);
for(int i=1;i<=3;i++){
ll cur=max(calc(ver[v][i],dver[x][i]),calc(ver[x][i],dver[v][i]))-2*dcst[x];
ans=max(ans,cur);
}
for(int i=1;i<=3;i++)
merge(ver[x][i],ver[v][i]),merge(dver[x][i],dver[v][i]);
}
}
void work(){
T=::T;
dfs(root,0);
}
}
int Q[N<<1],tot;
void afs(int x,int f,int c,int d){
ans=max(ans,T[1].dis(x,root)+T[2].dis(x,root)+T[0].dis(x,root));
Q[++tot]=x; IT::tp[x]=c; IT::cst[x]=T[2].dis(x,root)-(d?df[root]:-df[root]);
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f && !vis[E[i].t]) afs(E[i].t,x,c,d);
}
void solve(int x){
expl(x,0); imax=1<<30; isz=size[x]; getroot(x,0);
int cur=root; vis[cur]=1; tot=0;
for(int i=G[cur],j=1;i;i=E[i].nx,j++)
if(!vis[E[i].t]) afs(E[i].t,0,j,E[i].d);
//Q[++tot]=x; IT::tp[x]=0;
IT::build(Q,tot);
IT::work();
for(int i=G[cur];i;i=E[i].nx)
if(!vis[E[i].t]) solve(E[i].t);
}
void PutAns(ll x){
if(x>=10) PutAns(x/10); putchar(x%10+'0');
}
int main(){
read(n);
for(int i=1;i<=(n<<1);i++) lg2[i]=lg2[i-1]+((1<<lg2[i-1]+1)==i);
for(int k=0;k<3;k++){
tree *cur=T+k;
for(int i=1;i<n;i++){
int x,y; ll w;
read(x); read(y); read(w);
assert(x<=n && y<=n);
cur->addedge(x,y,w);
}
cur->dfs(1,0); cur->Pre();
}
dfs(T[2].G,T[2].E,1,0);
solve(1);
PutAns(ans); putchar('\n');
return 0;
}