题意:给你三棵树,求两个点,使得他们在三棵树上的距离和最大,输出最大距离
显然第1,2棵树分别为边分治,虚树,第3棵不会啊QWQ
[d_1[i]+d_2[i]+d_1[j]+d_2[j]-2*d_2[lca]
]
枚举(lca),答案就与最后一项无关了,加上第3可树
[ans=d_1[i]+d_2[i]+d_1[j]+d_2[j]+dis_3(i,j)
]
第3棵树,每个点新建一个(i`)向(i)连(d_1[i]+d_2[i])的边权,于是求满足分别是集合(L/R)内的点的最长路径
最长路径的点只可能是L,R,分别的直径的两点
于是虚树上DP
(f[i][0/1],i)子树内染色为0/1的点集的最远点对
合并前拿(f[x][0],f[v][1])和(f[x][1],f[v][0])更新答案即可,注意加上之前边分时作为重心的边,减去第二棵树上枚举的lca即x的距离*2
调题部分:
pre_e和e的混用
虚树DP后的清零节点
虚树建立后起点问题
虚树栈的清零地方,憨憨了st预处理时若不限制范围,肯会超出序列长度RE
for(int j=1; j<=lg[tim]; j++) for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间 mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]); //!!i+(1<<(j-1))<=tim;
//starusc
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int x=0,f=1;
char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c)) {
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return f==1?x:-x;
}
const int N=1e5+4;
int n,ans,extra_w,d1[N<<1],d2[N],d3[N],col[N];
vector<int>key;
namespace t3 {
struct edge {
int v,w,nxt;
} e[N<<1];
int first[N],cnt;
inline void add(int u,int v,int w) {
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
void dfs_1(int x,int fa) {
dep[x]=dep[fa]+1;
dfn[x]=++tim;
st[tim]=dep[x];
idx[tim]=x;
for(int i=first[x],v; i; i=e[i].nxt) {
v=e[i].v;
if(v==fa)continue;
d3[v]=d3[x]+e[i].w;
dfs_1(v,x);
st[++tim]=dep[x];
idx[tim]=x;
}
}
inline int gmin(int x,int y) {
return st[x]<st[y]?x:y;
}
inline int findlca(int x,int y) {
x=dfn[x];
y=dfn[y];
if(x>y)x^=y^=x^=y;
int k=lg[y-x+1];
return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
}
inline int dis(int x,int y) {
if(!x||!y)return -1;
return d1[x]+d2[x]+d3[x]+d1[y]+d2[y]+d3[y]-d3[findlca(x,y)]*2;
}
inline void build() {
for(int i=1,u,v,w; i<n; i++) {
u=read();
v=read();
w=read();
add(u,v,w);
add(v,u,w);
}
dfs_1(1,0);
for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
for(int i=1; i<=tim; i++)mn[i][0]=i;
for(int j=1; j<=lg[tim]; j++)
for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间
mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
}
namespace t2 {
struct edge {
int v,w,nxt;
} E[N<<1];
int first[N],cnt;
inline void add(int u,int v,int w) {
E[++cnt].v=v;
E[cnt].w=w;
E[cnt].nxt=first[u];
first[u]=cnt;
}
int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
void dfs_1(int x,int fa) {
dep[x]=dep[fa]+1;
dfn[x]=++tim;
st[tim]=dep[x];
idx[tim]=x;
for(int i=first[x],v; i; i=E[i].nxt) {
v=E[i].v;
if(v==fa)continue;
d2[v]=d2[x]+E[i].w;
dfs_1(v,x);
st[++tim]=dep[x];
idx[tim]=x;
}
}
inline int gmin(int x,int y) {
return st[x]<st[y]?x:y;
}
inline int findlca(int x,int y) {
x=dfn[x];
y=dfn[y];
if(x>y)x^=y^=x^=y;
int k=lg[y-x+1];
return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
}
inline void build() {
for(int i=1,u,v,w; i<n; i++) {
u=read();
v=read();
w=read();
add(u,v,w);
add(v,u,w);
}
dfs_1(1,0);
for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
for(int i=1; i<=tim; i++)mn[i][0]=i;
for(int j=1; j<=lg[tim]; j++)
for(int i=1; i+(1<<(j-1))<=tim; i++)
mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
inline bool comp(int x,int y) {
return dfn[x]<dfn[y];
}
int top,sta[N];
vector<int>e[N],clr;
inline void insert(int x) {
if(top<2) {
sta[++top]=x;
return;
}
int lca=findlca(x,sta[top]);
if(lca==sta[top]) {
sta[++top]=x;
return;
}
while(top>1&&dfn[sta[top-1]]>=dfn[lca]) {
e[sta[top-1]].push_back(sta[top]);
top--;
}
if(sta[top]!=lca) {
e[lca].push_back(sta[top]);
sta[top]=lca;
}
sta[++top]=x;
}
struct poin {
int x,y;
poin(int xx=0,int yy=0):x(xx),y(yy) {}
} f[N][2];
inline poin operator *(const poin &a,const poin &b) {
static int tmp,tmp2;
static poin ret;
ret=a;
tmp=t3::dis(a.x,a.y);
tmp2=t3::dis(b.x,b.y);
if(tmp2>tmp) {
tmp=tmp2;
ret=poin(b.x,b.y);
}
tmp2=t3::dis(a.x,b.x);
if(tmp2>tmp) {
tmp=tmp2;
ret=poin(a.x,b.x);
}
tmp2=t3::dis(a.x,b.y);
if(tmp2>tmp) {
tmp=tmp2;
ret=poin(a.x,b.y);
}
tmp2=t3::dis(b.x,a.y);
if(tmp2>tmp) {
tmp=tmp2;
ret=poin(b.x,a.y);
}
tmp2=t3::dis(a.y,b.y);
if(tmp2>tmp) {
tmp=tmp2;
ret=poin(a.y,b.y);
}
return ret;
}
inline int calc(const poin &a,const poin &b) {
return max(max(t3::dis(a.x,b.x),t3::dis(a.x,b.y)),max(t3::dis(a.y,b.x),t3::dis(a.y,b.y)));
}
void dp(int x) {
clr.push_back(x);
if(col[x])f[x][col[x]-1]=poin(x,x);
for(auto v:e[x]) {
dp(v);
ans=max(ans,calc(f[x][0],f[v][1])-d2[x]*2+extra_w);
ans=max(ans,calc(f[x][1],f[v][0])-d2[x]*2+extra_w);
f[x][0]=f[x][0]*f[v][0];
f[x][1]=f[x][1]*f[v][1];
}
}
inline void solve() {
if(key.empty())return;
sort(key.begin(),key.end(),comp);
top=0;//!
for(auto v:key)insert(v);
while(top>1) {
e[sta[top-1]].push_back(sta[top]);
top--;
}
dp(sta[1]);//
for(auto v:clr) {
f[v][0]=f[v][1]=poin(0,0);
e[v].clear();
d1[v]=0;
}
key.clear();
clr.clear();
}
}
namespace t1 {
struct edge {
int v,w,nxt;
} e[N<<2],pre_e[N<<1];
int first[N<<1],pre_fir[N],cnt=1,pre_cnt;
inline void add(int u,int v,int w) {
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
inline void pre_add(int u,int v,int w) {
pre_e[++pre_cnt].v=v;
pre_e[pre_cnt].w=w;
pre_e[pre_cnt].nxt=pre_fir[u];
pre_fir[u]=pre_cnt;
}
int tot,sum,rt,rt_min,vis[N<<2],siz[N<<1];
void rebuild(int x,int fa) {
for(int i=pre_fir[x],nw=0,v; i; i=pre_e[i].nxt) {
v=pre_e[i].v;
if(v==fa)continue;
if(!nw) {
add(x,v,pre_e[i].w);
add(v,x,pre_e[i].w);
nw=x;
} else {
add(nw,++tot,0);
add(tot,nw,0);
nw=tot;
add(nw,v,pre_e[i].w);
add(v,nw,pre_e[i].w);
}
rebuild(v,x);
}
}
inline void build() {
for(int i=1,u,v,w; i<n; i++) {
u=read();
v=read();
w=read();
pre_add(u,v,w);
pre_add(v,u,w);
}
tot=n;
rebuild(1,0);
sum=tot;
}
void findrt(int x,int fa) {
siz[x]=1;
for(int i=first[x],v; i; i=e[i].nxt) {
v=e[i].v;
if(v==fa||vis[i])continue;
findrt(v,x);
siz[x]+=siz[v];
if(!rt||vis[rt]||max(siz[v],sum-siz[v])<rt_min) {
rt_min=max(siz[v],sum-siz[v]);
rt=i;
}
}
}
void getdis(int x,int fa,int c) {
siz[x]=1;
if(x<=n) {
col[x]=c;
key.push_back(x);
}
for(int i=first[x],v; i; i=e[i].nxt) {
v=e[i].v;
if(v==fa||vis[i])continue;
d1[v]=d1[x]+e[i].w;
getdis(v,x,c);
siz[x]+=siz[v];
}
}
void solve(int x) {
if(sum==1)return;
findrt(x,0);
int gr=e[rt].v,gl=e[rt^1].v;
vis[rt]=vis[rt^1]=1;
d1[gl]=d1[gr]=0;
extra_w=e[rt].w;
getdis(gl,0,1);
getdis(gr,0,2);
t2::solve();
sum=siz[gl];
solve(gl);
sum=siz[gr];
solve(gr);
}
}
signed main() {
n=read();
t1::build();
t2::build();
t3::build();
t1::solve(1);
cout<<ans;
return (0-0);
}
//pre_e和e的混用
//虚树DP后的清零节点
//虚树建立后起点问题
//虚树栈的清零地方,憨憨了