好久以前开的坑.
到今天才填上.
首先考虑队第一颗树边分,然后分成两个集合\(L,R\),在第二棵树上建出虚树,在每个路径\(lca\)处统计答案,维护点集的直径只有正权很好维护.
#include <bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int,int> p;
typedef pair<p,p> pp;
struct edge{int x;ll w;bool operator ==(const edge &_) const{return x==_.x&&w==_.w;}void print(){cerr<<"{"<<x<<","<<w<<"} ";}
};
typedef vector<edge> vi;
typedef vector<vector<edge> > vvi;
vi operator +(const vi &a,const vi &b){vi ret(a);ret.insert(ret.end(),b.begin(),b.end());return ret;
}
ostream& operator <<(ostream &ou,const p &a){return ou<<"["<<a.first<<","<<a.second<<"]";
}
const int N=100010;
int n;
namespace Tree3{vvi TG;int dep[N],top[N],fa[N],sz[N],son[N];ll dis[N];int getlca(int x,int y){while (top[x]!=top[y]){if (dep[top[x]]>dep[top[y]]) swap(x,y);y=fa[top[y]];}return dep[x]<dep[y]?x:y;}ll getdis(int x,int y){return dis[x]+dis[y]-2*dis[getlca(x,y)];}void Dfs(int x,int f=0){fa[x]=f;dep[x]=dep[f]+1;sz[x]=1;for (auto i:TG[x])if (i.x!=f){dis[i.x]=dis[x]+i.w;Dfs(i.x,x);sz[x]+=sz[i.x];if (sz[i.x]>sz[son[x]]) son[x]=i.x;}}void Sfd(int x,int tp,int f=0){top[x]=tp;if (son[x]) Sfd(son[x],tp,x);for (auto i:TG[x])if (i.x!=f&&i.x!=son[x]) Sfd(i.x,i.x,x);}void read(){TG.resize(n+1);for (int i=1; i<n; ++i){int x,y;ll w;scanf("%d%d%lld",&x,&y,&w);TG[x].push_back({y,w});TG[y].push_back({x,w});}Dfs(1);Sfd(1,1);}
}
namespace Tree2{const ll INF=1e18;vvi TG;int dep[N],col[N],clk,dfn[N],fa[N][17],dtime;ll dis[N],cost[N],ret;pp diameter[N];vector<int> E[N];int getlca(int x,int y){if (dep[x]>dep[y]) swap(x,y);for (int i=16; i>=0; --i) if (dep[fa[y][i]]>=dep[x]) y=fa[y][i];if (x==y) return x;for (int i=16; i>=0; --i) if (fa[y][i]!=fa[x][i]) x=fa[x][i],y=fa[y][i];return fa[x][0];}void Dfs(int x,int f=0){fa[x][0]=f;for (int i=1; i<17; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];dfn[x]=++clk;dep[x]=dep[f]+1;for (auto i:TG[x])if (i.x!=f){dis[i.x]=dis[x]+i.w;Dfs(i.x,x);}}void read(){//cerr<<"readbegin2"<<endl;TG.resize(n+1);for (int i=1; i<n; ++i){int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);TG[u].push_back({v,w});TG[v].push_back({u,w});}Dfs(1);//cerr<<"readend2"<<endl;}bool cmp(const edge &a,const edge &b){return dfn[a.x]<dfn[b.x];}ll calc(int a,int b){if (!(a&&b)) return (a||b)?-INF:-2*INF;if (a==b) return 0;//cerr<<"calc"<<a<<" "<<b<<" "<<cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b)<<" "<<dis[a]+dis[b]<<endl;return cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b);}ll calc(const p &a,const p &b){return max(max(calc(a.first,b.second),calc(a.first,b.first)),max(calc(a.second,b.first),calc(a.second,b.second)));}p operator +(const p &a,int b){ll t=calc(a.first,a.second);ll t2=calc(a.first,b);ll t3=calc(a.second,b);return max(t2,t3)>t?p({t2>=t3?a.first:a.second,b}):a;}p operator +(const p &a,const p &b){return (a+b.first)+b.second;}pp operator +(const pp &a,const pp &b){return {a.first+b.first,a.second+b.second};}p tr(int x){return {x,x};}int tim,vis[N],faf[N];void dfs(int x){//cerr<<"dfs on virtual tree:"<<x<<" "<<dis[x]<<endl;diameter[x]={tr(col[x]&1?x:0),tr(col[x]&1?0:x)};//cerr<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;for (auto i:E[x]){dfs(i);ret=max(ret,calc(diameter[x].first,diameter[i].second)-dis[x]*2);ret=max(ret,calc(diameter[x].second,diameter[i].first)-dis[x]*2);//cerr<<"aftmerge"<<x<<" "<<i<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<" "<<dis[x]<<endl;diameter[x]=diameter[x]+diameter[i];}faf[x]=0;E[x].clear();//cerr<<"endi"<<x<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;}ll build_virtual_tree(vi a){sort(a.begin(),a.end(),cmp);stack<int> s;int rt=a[0].x;ret=0;vector<int> vim;for (auto i:a){vim.push_back(i.x);if (s.size()){int lca=getlca(s.top(),i.x);vim.push_back(lca);//cerr<<"build"<<i.x<<" "<<lca<<" "<<faf[1]<<endl;if (dep[lca]<dep[rt]) rt=lca;while (dep[faf[s.top()]]>dep[lca]) s.pop();bool cd=(faf[s.top()]!=lca);if (cd) faf[lca]=faf[s.top()];if (s.top()!=lca) faf[s.top()]=lca;s.pop();if (cd) s.push(lca);faf[i.x]=lca;}s.push(i.x);}++tim;for (auto i:vim)if (vis[i]<tim){vis[i]=tim;//cerr<<"fa"<<i<<" "<<faf[i]<<endl;E[faf[i]].push_back(i);}//cerr<<"ESZE"<<E[rt].size()<<" "<<rt<<endl;//exit(0);dfs(rt);return ret;}ll main(vi &u,vi &v){if (!(u.size()&&v.size())) return -INF;++dtime;for (auto i:u){col[i.x]=dtime;cost[i.x]=i.w;}++dtime;for (auto i:v){col[i.x]=dtime;cost[i.x]=i.w;}return build_virtual_tree(u+v);}
}
namespace Tree1{vvi G,TG;int sz[N<<1];int aa,bb,cnt,val;ll ans,ww;void dfs(int x,int f){for (auto i:TG[x])if (i.x!=f) dfs(i.x,x);int now=x;for (auto i:TG[x])if (i.x!=f){G[now].push_back({i.x,i.w});G[i.x].push_back({now,i.w});//cerr<<"cdr"<<now<<" "<<i.x<<" "<<i.w<<endl;++cnt;G[now].push_back({cnt,0});G[cnt].push_back({now,0});//cerr<<"car"<<now<<" "<<cnt<<" "<<0<<endl;now=cnt;}}void getsz(int x,int f=0){sz[x]=1;for (auto i:G[x])if (i.x!=f){getsz(i.x,x);sz[x]+=sz[i.x];}}void dfs(int x,int f,ll len){if (max(val-sz[x],sz[x])<max(val-sz[aa],sz[aa])){aa=x;bb=f;ww=len;}for (auto i:G[x])if (i.x!=f) dfs(i.x,x,i.w);}void Getpoint(int x,vi &g,int f=0,ll dis=0){if (x<=n) g.push_back({x,dis});for (auto i:G[x]) if (i.x!=f) Getpoint(i.x,g,x,dis+i.w);}void BF(int x){//cerr<<"BF"<<x<<endl;getsz(x);//cerr<<"getend"<<endl;aa=x;bb=0;val=sz[x];if (val==1) return;//cerr<<"dfsbegin"<<endl;dfs(x,0,0);//cerr<<"dfsend"<<aa<<" "<<bb<<" "<<ww<<" "<<(find(G[aa].begin(),G[aa].end(),edge{bb,ww})==G[aa].end())<<endl;G[aa].erase(find(G[aa].begin(),G[aa].end(),edge{bb,ww}));G[bb].erase(find(G[bb].begin(),G[bb].end(),edge{aa,ww}));//cerr<<"???"<<endl;vi u,v;Getpoint(aa,u);Getpoint(bb,v);//cerr<<"U:"<<endl;//for (auto i:u) i.print();//cerr<<endl<<"V:"<<endl;//for (auto i:v) i.print();//cerr<<endl<<"What's the edge:"<<aa<<" "<<bb<<" "<<ww<<endl;ans=max(ans,Tree2::main(u,v)+ww);//cerr<<"inthisans:"<<ans<<endl;//exit(0);int tmp=bb;BF(aa);BF(tmp);}void main(){scanf("%d",&n);TG.resize(n+1);G.resize(2*n);cnt=n;for (int i=1; i<n; ++i){int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);TG[u].push_back({v,w});TG[v].push_back({u,w});}Tree2::read();Tree3::read();/*for (int i=1; i<=n; ++i)for (int j=1; j<=n; ++j)cerr<<i<<" "<<j<<" "<<Tree3::getdis(i,j)<<endl;*/dfs(1,0);BF(1);cout<<ans;}
}
int main(){Tree1::main();
}