显然是 Boruvka,考虑一次怎么求边。
一棵树的时候是简单的,树形 dp 即可。考虑第二棵树是菊花怎么做,显然这个问题等价于完全图上的边权形如 \(D(x,y)+a_x+a_y\),这也是简单的,推广这个做法,对第二棵树点分治,每次对不同子树中的点统计贡献,这样每个点就有了两个属性(原图上的颜色、第二棵树上所在的子树),不妨分别记为 \(col_i\) 和 \(bel_i\),那我们就是要找两个 \(bel_i\neq bel_j\),\(col_i\neq col_j\) 的点。多记一下状态大力分类讨论转移可以解决。考虑是否真要这么麻烦呢?如果我们不区分 \(bel_i\),考虑两个点 \((i,j)\),他们可能会在点分治时产生贡献,但一定不是最优,考虑两者在不同子树一定比当前优,因此无需考虑区分 \(bel_i\)。
还有一个问题就是如果每次点分治时都对原树做一遍 dp,复杂度为 \(O(n^2)\)。考虑点分治时只会有 \(O(n\log n)\) 个点有用,因此只需对其建虚树即可,可以做到 \(O(n\log^3 n)\),由于每次做 Boruvka 的时候虚树形态相同,因此可以提前预处理出来。时间复杂度 \(O(n\log^2 n)\)。
代码里面有份暴力,所以看上去比较长。
#include<bits/stdc++.h>
namespace brute_force{
// #include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)template<typename T>
void read(T &x){x=0;int f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();x*=f;
}std::stack<char>st;
template<typename T>
void print(T x){if(x==0) putchar('0');if(x<0) putchar('-'),x=-x;while(st.size()) st.pop();while(x) st.push((char)('0'+x%10)),x/=10;while(st.size()) putchar(st.top()),st.pop();
}template<typename T>
void printsp(T x){print(x),putchar(' ');
}template<typename T>
void println(T x){print(x),putchar('\n');
}template<typename T,typename I>
bool chkmin(T &a,I b){if(a>b) return a=b,1;return 0;
}template<typename T,typename I>
bool chkmax(T &a,I b){if(a<b) return a=b,1;return 0;
}template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){vec[u].push_back(v);
}template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){vec[u].push_back({v,w});
}template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){addedge(vec,u,v),addedge(vec,v,u);
}template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){addedge(vec,u,v,w),addedge(vec,v,u,w);
}bool Mbe;const int inf=1e18,MOD1=998244353,MOD2=1e9+7;const int maxn=1e3+10;vpair a[maxn],b[maxn],c[maxn];int n,dis1[maxn],dis2[maxn],f[maxn][20],g[maxn][20],dep1[maxn],dep2[maxn];struct edge{int u,v,w;
}d[maxn*maxn];namespace DSU{int to[maxn];void init_(){for(int i=1;i<=n;i++) to[i]=i;}int go(int x){if(to[x]==x) return x;return to[x]=go(to[x]);}bool merge(int x,int y){x=go(x),y=go(y);if(x==y) return 0;to[x]=y;return 1;}
}using namespace DSU;void dfs1(int p,int fa){dep1[p]=dep1[fa]+1;f[p][0]=fa;for(pii i:a[p]){if(i.fi==fa) continue;dis1[i.fi]=dis1[p]+i.se;dfs1(i.fi,p);}
}void dfs2(int p,int fa){dep2[p]=dep2[fa]+1;g[p][0]=fa;for(pii i:b[p]){if(i.fi==fa) continue;dis2[i.fi]=dis2[p]+i.se;dfs2(i.fi,p);}
}edge made(int u,int v,int w){edge res;res.u=u,res.v=v,res.w=w;return res;
}void init(){for(int j=1;j<=19;j++)for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[g[i][j-1]][j-1];
}int lca1(int x,int y){if(dep1[x]<dep1[y]) std::swap(x,y);for(int i=19;i>=0;i--)if(dep1[f[x][i]]>=dep1[y]) x=f[x][i];if(x==y) return x;for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];return f[x][0];
}int lca2(int x,int y){if(dep2[x]<dep2[y]) std::swap(x,y);for(int i=19;i>=0;i--)if(dep2[g[x][i]]>=dep2[y]) x=g[x][i];if(x==y) return x;for(int i=19;i>=0;i--)if(g[x][i]!=g[y][i]) x=g[x][i],y=g[y][i];return g[x][0];
}bool cmp(edge s1,edge s2){return s1.w<s2.w;
}bool Men;void main(){debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);read(n);int x,y,v;#define sb(a) read(x),read(y),read(v),addd(a,x,y,v)for(int i=1;i<n;i++) sb(a);for(int i=1;i<n;i++) sb(b);dfs1(1,0),dfs2(1,0),init();int cnt=0;for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++){int cost=dis1[i]+dis1[j]-2*dis1[lca1(i,j)]+dis2[i]+dis2[j]-2*dis2[lca2(i,j)];// addd(a,i,j,cost);d[++cnt].u=i,d[cnt].v=j,d[cnt].w=cost;}init_();std::sort(d+1,d+cnt+1,cmp);int cost=0;std::vector<edge>vec;for(int i=1;i<=cnt;i++){int u=d[i].u,v=d[i].v,w=d[i].w;if(!merge(u,v)) continue;cost+=w;vec.push_back(made(u,v,w));// addd(c,u,v);}println(cost);for(edge i:vec) printf("%lld %lld %lld\n",i.u,i.v,i.w);// for(int i=1;i<=n;i++)// for(int j:vost)debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}}
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)template<typename T>
void read(T &x){x=0;int f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();x*=f;
}std::stack<char>st;
template<typename T>
void print(T x){if(x==0) putchar('0');if(x<0) putchar('-'),x=-x;while(st.size()) st.pop();while(x) st.push((char)('0'+x%10)),x/=10;while(st.size()) putchar(st.top()),st.pop();
}template<typename T>
void printsp(T x){print(x),putchar(' ');
}template<typename T>
void println(T x){print(x),putchar('\n');
}template<typename T,typename I>
bool chkmin(T &a,I b){if(a>b) return a=b,1;return 0;
}template<typename T,typename I>
bool chkmax(T &a,I b){if(a<b) return a=b,1;return 0;
}template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){vec[u].push_back(v);
}template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){vec[u].push_back({v,w});
}template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){addedge(vec,u,v),addedge(vec,v,u);
}template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){addedge(vec,u,v,w),addedge(vec,v,u,w);
}bool Mbe;const int inf=1e18,MOD1=998244353,MOD2=1e9+7;const int maxn=1e5+10;int n,num,sz[maxn],mx[maxn],dfn[maxn],edfn[maxn*2],cnt,tot,fir[maxn],fdfn[maxn],mt[maxn*2][18],lg[maxn*2],dis[maxn],bel[maxn],val[maxn],best[maxn],sec[maxn],bcol[maxn],seccol[maxn];bool vis[maxn];vint col[maxn],vec;vpair a[maxn],b[maxn],mst;struct edge{int u,v,w;
};edge newedge(int u,int v,int w){edge res;res.u=u,res.v=v,res.w=w;return res;
}struct Tree{int rt;std::vector<edge>a;
}dot[maxn];namespace LCA{void dfs(int p,int fa){dfn[p]=++cnt,edfn[++tot]=dfn[p];fir[p]=tot,fdfn[cnt]=p;for(pii i:a[p]){if(i.fi==fa) continue;dis[i.fi]=dis[p]+i.se;dfs(i.fi,p);edfn[++tot]=dfn[p];}}void init(){dfs(1,0);for(int i=1;i<=tot;i++) mt[i][0]=edfn[i];for(int j=1;j<20;j++)for(int i=1;i+(1ll<<j)-1<=tot;i++) mt[i][j]=std::min(mt[i][j-1],mt[i+(1ll<<(j-1))][j-1]);lg[0]=-1;for(int i=1;i<=tot;i++) lg[i]=lg[i>>1]+1;}int query(int l,int r){if(l>r) std::swap(l,r);int len=r-l+1;return std::min(mt[l][lg[len]],mt[r-(1ll<<lg[len])+1][lg[len]]);}int lca(int x,int y){return fdfn[query(fir[x],fir[y])];}
}void pdfs(int p,int fa){vec.push_back(p);sz[p]=1;mx[p]=0;for(pii i:b[p]){if(i.fi==fa||vis[i.fi]) continue;pdfs(i.fi,p);sz[p]+=sz[i.fi];chkmax(mx[p],sz[i.fi]);}// debug("p=%lld sz=%lld mx=%lld\n",p,sz[p],mx[p]);
}int zx,siz;void findrt(int p,int fa,int gt){// debug("p=%lld gt=%lld mx=%llld siz=%lld\n",p,gt,mx[p],siz);;if(std::max(gt,mx[p])<siz) zx=p,siz=std::max(gt,mx[p]);for(pii i:b[p]){if(i.fi==fa||vis[i.fi]) continue;findrt(i.fi,p,gt+sz[p]-sz[i.fi]);}
}bool cmp_dfn(int x,int y){return dfn[x]<dfn[y];
}void dfs(int p){vec.clear();siz=inf;pdfs(p,0),findrt(p,0,0);vint nd;// debug("zx=%lld\n",zx);std::sort(vec.begin(),vec.end(),cmp_dfn);// for(int i:vec) debug("i=%lld\n",i);for(int i=1;i<vec.size();i++){int lca=LCA::lca(vec[i],vec[i-1]);nd.push_back(lca);// debug("%lld %lld lca:%lld\n",vec[i],vec[i-1],lca);// dot[zx].a.push_back(newedge(vec[i],lca,dis[vec[i]]-dis[lca]));// debug("%lld - %lld > %lld\n",vec[i],lca,dis[vec[i]]-dis[lca]); // debug("zx=%lld %lld %lld\n",zx,vec[i])}for(int i:nd) vec.push_back(i);std::sort(vec.begin(),vec.end(),cmp_dfn);auto z=std::unique(vec.begin(),vec.end());auto i=vec.begin();int las=*i;i++;for(;i!=z;i++){int now=*i;int lca=LCA::lca(las,now);dot[zx].a.push_back(newedge(now,lca,dis[now]-dis[lca]));// debug("%lld - %lld > %lld\n",now,lca,dis[now]-dis[lca]);las=now;}int mi=inf;for(int i:vec) if(chkmin(mi,dfn[i])) dot[zx].rt=i;vis[zx]=1;for(pii i:b[zx]) if(!vis[i.fi]) dfs(i.fi);
}int cost;namespace DSU{int to[maxn];void init(){for(int i=1;i<=n;i++) to[i]=i;}int go(int p){if(to[p]==p) return p;return to[p]=go(to[p]);}void merge(int x,int y){x=go(x),y=go(y);if(x==y) return ;to[x]=y;}
}int ok[maxn],tim;namespace getMST{int sz[maxn],mx[maxn],zx,siz,cho[maxn],id[maxn];bool vis[maxn];vpair c[maxn];namespace VT{void dfs(int p,int fa){for(pii i:c[p]){if(i.fi==fa) continue;dfs(i.fi,p);}if(ok[p]!=tim) val[p]=inf;best[p]=val[p],bcol[p]=bel[p];sec[p]=inf,seccol[p]=0;for(pii i:c[p]){if(i.fi==fa) continue;if(best[i.fi]+i.se<=best[p]){if(bcol[i.fi]==bcol[p]) best[p]=best[i.fi]+i.se;else sec[p]=best[p],seccol[p]=bcol[p],best[p]=best[i.fi]+i.se,bcol[p]=bcol[i.fi];}else if(best[i.fi]+i.se<=sec[p]&&bcol[p]!=bcol[i.fi]){sec[p]=best[i.fi]+i.se,seccol[p]=bcol[i.fi];}if(sec[i.fi]+i.se<=sec[p]&&seccol[i.fi]!=bcol[p]) sec[p]=sec[i.fi]+i.se,seccol[p]=seccol[i.fi];}// best[p]+=val[p],sec[p]+=val[p];// debug("p=%lld best=%lld bcol=%lld sec=%lld seccol=%lld\n",p,best[p],bcol[p],sec[p],seccol[p]);}void pdfs(int p,int fa,int bst,int snd,int bstcol,int sndcol){int w=inf;if(bel[p]!=bcol[p]) chkmin(w,best[p]);if(bstcol!=bel[p]) chkmin(w,bst);if(bel[p]!=seccol[p]) chkmin(w,sec[p]);if(bel[p]!=sndcol) chkmin(w,snd);if(chkmin(cho[bel[p]],w+val[p])){if(w==best[p]&&bcol[p]!=bel[p]) id[bel[p]]=bcol[p];else if(w==bst&&bstcol!=bel[p]) id[bel[p]]=bstcol;else if(w==snd&&sndcol!=bel[p]) id[bel[p]]=sndcol;else id[bel[p]]=seccol[p];}// debug("p=%lld bst=%lld snd=%lld bstcol=%lld sndcol=%lld w=%lld cho=%lld id=%lld\n",p,bst,snd,bstcol,sndcol,w,cho[bel[p]],id[bel[p]]);int bw=std::min(std::min(std::min(bst,snd),best[p]),sec[p]),bc;int cw=inf,cc;if(bw==best[p]) bc=bcol[p];else bc=bstcol;if(snd<cw&&sndcol!=bc) cw=snd,cc=sndcol;if(sec[p]<cw&&seccol[p]!=bc) cw=sec[p],cc=seccol[p];// if(cw==snd) cc=sndcol;// else cc=seccol[p];if(bw==best[p]&&bcol[p]!=bstcol&&bst<cw) cw=bst,cc=bstcol;if(bw==bst&&bstcol!=bcol[p]&&best[p]<cw) cw=best[p],cc=bcol[p];for(pii i:c[p]){if(i.fi==fa) continue;pdfs(i.fi,p,bw+i.se,cw+i.se,bc,cc);}}}void pdfs(int p,int fa){sz[p]=1,mx[p]=0,ok[p]=tim;for(pii i:b[p]){if(i.fi==fa||vis[i.fi]) continue;pdfs(i.fi,p);sz[p]+=sz[i.fi];chkmax(mx[p],sz[i.fi]);}}void findrt(int p,int fa,int gt){if(chkmin(siz,std::max(mx[p],gt))) zx=p;for(pii i:b[p]){if(i.fi==fa||vis[i.fi]) continue;;findrt(i.fi,p,gt+sz[p]-sz[i.fi]);}}void getval(int p,int fa){for(pii i:b[p]){if(i.fi==fa||vis[i.fi]) continue;val[i.fi]=val[p]+i.se;// debug("i.fi=%lld val=%lld p=%lld i.se=%lld\n",i.fi,val[i.fi],p,i.se);getval(i.fi,p);}}void dfs(int p){tim++;siz=inf;pdfs(p,0),findrt(p,0,0);p=zx;// debug("zx=%lld\n",zx);val[p]=0,getval(p,0);for(edge i:dot[p].a){addd(c,i.u,i.v,i.w);}VT::dfs(dot[p].rt,0),VT::pdfs(dot[p].rt,0,inf,inf,-1,-1);for(edge i:dot[p].a) c[i.u].clear(),c[i.v].clear();vis[zx]=1;for(pii i:b[p]){if(vis[i.fi]) continue;dfs(i.fi);}}int to[maxn];void Boruvka(){// debug("ok\n");// DSU::init();for(int i=1;i<=n;i++)for(int j:col[i]) bel[j]=i,cho[i]=inf,id[i]=i;//,debug("i=%lld j=%lld\n",i,j);memset(vis,0,sizeof(vis));dfs(1);for(int i=1;i<=n;i++){if(!col[i].size()) continue;if(DSU::go(i)==DSU::go(id[i])) continue;// if(id[i]<i) continue;cost+=cho[i];num--;DSU::merge(i,id[i]);// for(int j:col[id[i]]) col[i].push_back(j);}for(int i=1;i<=n;i++) col[i].clear();for(int i=1;i<=n;i++) col[DSU::go(i)].push_back(i);}
}bool Men;signed main(){// freopen("data.in","r",stdin),freopen("my.out","w",stdout);// brute_force::main();// return 0;debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);read(n);for(int i=1;i<n;i++){int x,y,v;read(x),read(y),read(v);addd(a,x,y,v);}LCA::init();for(int i=1;i<n;i++){int x,y,v;read(x),read(y),read(v);addd(b,x,y,v);}dfs(1);for(int i=1;i<=n;i++) col[i].push_back(i);num=n;DSU::init();while(num!=1) getMST::Boruvka();println(cost);debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
/*
5
2 1 12
3 1 3
4 2 6
5 4 1
2 1 9
3 2 14
4 3 4
5 3 135
2 1 14
3 2 6
4 1 13
5 4 14
2 1 8
3 2 4
4 3 15
5 1 7*/