WC2018 通道
好久以前开的坑.
到今天才填上.
首先考虑队第一颗树边分,然后分成两个集合\(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();
}