题意
给出三棵 n(≤105) n ( ≤ 10 5 ) 个点的树,边有边权 Li(≤1012) L i ( ≤ 10 12 ) ,求 max1≤i,j≤n(dis1(i,j)+dis2(i,j)+dis3(i,j)) m a x 1 ≤ i , j ≤ n ( d i s 1 ( i , j ) + d i s 2 ( i , j ) + d i s 3 ( i , j ) ) 。
写在前面的自说自话
上一次更这边的blog…是两个月之前?最近一直
没有写题没遇到比较值得放进blog的题…然后我现在已经不知道什么难度的题应该写blog了…。
本来wc回来就想改的,但是因为考场上留下了「点分×点分写挂」的心理阴影就一直没改(可能还有个原因是当时没看懂题解里最后那句「多叉转二叉」是怎么转的)。至于现在…ctsc「点分×点分写挂」的心理阴影把那次的覆盖了…就可以安心改了(大雾
还是前几天ryf问到这个题才想起来的…正好最近没怎么写长代码题(如果考场上不算的话),翻出来写一写,然后写了半下午,调了半下午。
题解
大家可以去看课件呀
稍微简述一下…
两棵树的情况可以点分套点分考虑在 T1 T 1 的每个点 i i 上挂上 dep2(i) d e p 2 ( i ) 的贡献,之后在 T2 T 2 上枚 lca l c a ,把不在同一子树里的点对拎出来,到 T1 T 1 里求 max m a x 。
摘一条性质:「边权非负的图中,跨越集合 A,B A , B 的最长链的端点,一定是 A A 中最长链和 B B 中最长链的端点」
所以就可以在 T2 T 2 里自底向上合并,维护子树在 T1 T 1 中对应的最长链端点,因为带个 T1 T 1 里求 lca l c a ,复杂度带 log l o g 。
树*2+链就对 T3 T 3 那条链分治,计算过中点路径的贡献。把中点两边的点作为两种类型,贡献算出来,拿到一起建个 T2 T 2 上的虚树,合并时分别维护两种类型的点集即可。
(这步我看了半天一直觉得是双log的…因为虚树dfs序带个排序,但题解里似乎并不是…于是问l1ll5虚树有没有线性做法,l1ll5看了一眼题,告诉我这个在分治过程中可以归并上去…感觉自己很sb。)
树*3同理对 T3 T 3 点分。因为对于分治重心的每个分治子树,需要分别算它到其它子树的最长链,重心度数大就跪了,所以需要预处理转个二叉,也即在当前根的位置建一条链,边权都为零,之后把它的子节点依次挂到链上。
总复杂度 O(nlogn) O ( n l o g n ) 。
为什么题解里带了个 α α
代码
#include
#define N 200005
#define L 18
#define rg register int
#define upd(x) ans
using namespace std;
typedef long long ll;
int n,nn,d=-1,to[N],hd[N],lk[N],cnt,t,sz[N],a[N],b[N],tot;
ll len[N],ans,dep[N][L];
struct typ1
{
ll D[N];
int ln[N][L],st[N],de[N],re[N];
inline int lca(int x,int y)
{
if(x==y)return x;
x=re[x],y=re[y];if(x>y)swap(x,y);
rg z=st[y-x],u=ln[x][z],v=ln[y-(1<1 ][z];
return de[u]int x,int y)
{return D[x]+D[y]-(D[lca(x,y)]<<1);}
void dfs(int x)
{
ln[re[x]=t++][0]=x;
for(rg s,i=lk[x];i;i=hd[i])
if(!de[s=to[i]])
de[s]=de[x]+1,D[s]=D[x]+len[i],dfs(s),ln[t++][0]=x;
}
inline void rmq()
{
de[1]=1,dfs(1);
for(rg i=1;i1]+!!(i>>st[i-1]);
for(rg i=t-1;i>=0;--st[i--])
for(rg j=0;j1&&i+(1<1]=ln[i+((de[ln[i][j]]>de[ln[i+(1<0;
}
}T1,T2;
ll w,D[N],now,tmp;
inline void add(int u,int v)
{to[++cnt]=v,hd[cnt]=lk[u],len[cnt]=w,lk[u]=cnt;}
inline void cal(int u,int v)
{w=T2.D[v]-T2.D[u],add(u,v);}
int st[N],rec[N],no[N][4],u,v,tim[N],dfn;
bool ins[N];
inline ll dis(int x,int y)
{return x&&y?D[x]+D[y]+T1.dis(x,y):-1;}
inline void mx(int x,int y)
{tmp=dis(x,y);if(tmp>now)u=x,v=y,now=tmp;}
inline void find(int p,int q,int r,int s)
{now=-2,mx(p,r),mx(q,r),mx(p,s),mx(q,s);}
inline void find_(int p,int q,int r,int s)
{find(p,q,r,s);mx(p,q),mx(r,s);}
inline void uni(int x,int y)
{
find(no[x][0],no[x][2],no[y][1],no[y][3]);
upd(dis(u,v)-(w<<1));
find(no[x][1],no[x][3],no[y][0],no[y][2]);
upd(dis(u,v)-(w<<1));
find_(no[x][0],no[x][2],no[y][0],no[y][2]);
no[x][0]=u,no[x][2]=v;
find_(no[x][1],no[x][3],no[y][1],no[y][3]);
no[x][1]=u,no[x][3]=v;
}
void sol(int x)
{
register ll tp=D[x];D[x]+=dep[x][d];
no[x][ins[x]]=no[x][ins[x]|2]=tim[x]==dfn?x:0;
no[x][ins[x]^1]=no[x][2|ins[x]^1]=0;
for(rg s,i=lk[x];i;i=hd[i])
D[s=to[i]]=tp+len[i],sol(s),w=tp,uni(x,s);
}
inline void merge(int l,int m,int r)
{
tot=l;
for(rg i=l,j=m;i<m||jm&&T2.re[a[i]]0;
for(rg i=l,x,y,lst;im,x=a[i]=b[i],tim[x]=dfn,lk[x]=0;
if(tot)
{
y=T2.lca(st[tot],x);
for(lst=0;T2.de[st[tot]]>T2.de[y];tot--)
{
if(lst)cal(st[tot],lst);
lst=st[tot];
}
if(st[tot]^y)
lk[st[++tot]=y]=0;
if(lst)cal(y,lst);
}
st[++tot]=x;
}
for(;tot>1;tot--)cal(st[tot-1],st[tot]);
sol(st[1]);
}
struct typ2
{
int To[N<<1],Hd[N<<1],Lk[N],tp;
ll Len[N<<1];
bool vis[N];
inline void Add(int u,int v,ll w)
{To[++cnt]=v,Hd[cnt]=Lk[u],Len[cnt]=w,Lk[u]=cnt;}
inline void ad(int u,int v,ll w)
{Add(u,v,w),Add(v,u,w);}
void dfs(int x)
{
vis[x]=sz[x]=1;
if(hd[hd[lk[x]]]&&x<2||hd[hd[hd[lk[x]]]])
{
rg lst=0;
for(rg s,i=lk[x];i;i=hd[i])
if(!vis[s=to[i]])
{
dfs(s),ad(++n,s,len[i]),sz[n]=sz[s]+1;
if(lst)ad(n,lst,0),sz[n]+=sz[lst];
lst=n;
}
ad(x,n,0),sz[x]+=sz[n];
}
else for(rg s,i=lk[x];i;i=hd[i])
if(!vis[s=to[i]])
ad(x,s,len[i]),dfs(s),sz[x]+=sz[s];
}
int getr(int x,int y)
{
for(rg s,i=Lk[x];i;i=Hd[i])
if(sz[s=To[i]]>tp&&vis[s]&&s^y)
return getr(s,x);
return x;
}
void ini(int x,int y)
{
sz[x]=1;
for(rg s,i=Lk[x];i;i=Hd[i])
if(vis[s=To[i]]&&s^y)
dep[s][d]=dep[x][d]+Len[i],
ini(s,x),sz[x]+=sz[s];
}
void cet(int x,int y)
{
if(x<=nn)
upd(dep[x][d]+T1.dis(x,tp)+T2.dis(x,tp));
for(rg s,i=Lk[x];i;i=Hd[i])
if(rec[s=To[i]]>rec[tp]&&s^y)
cet(s,x);
}
void div(int x)
{
tp=sz[x]>>1;
vis[x=getr(x,x)]=0;
rec[x]=d++;ini(x,x);
rg l=t;
for(rg i=Lk[x],r=t,s;i;i=Hd[i])
if(vis[s=To[i]])
div(s),l0:0,r=t;
if(x<=nn)
{
for(rg i=t-1;;i--)
if(ix])
{
for(rg j=t;j>i;j--)
a[j]=a[j-1];a[i+1]=x;
break;
}
t++,tp=x,cet(x,x);
}
d--;
}
}T3;
inline void ini()
{
for(rg i=1;i<=n;i++)lk[i]=0;
for(rg i=1,u,v;i"%d%d%lld",&u,&v,&w),
add(u,v),add(v,u);
cnt=0;
}
int main()
{
scanf("%d",&n);nn=n;
ini(),T1.rmq();
ini(),T2.rmq();
ini(),T3.dfs(1);
for(rg i=nn+1;i<=n;i++)T3.vis[i]=1;
T3.div(1);
printf("%lld",ans);
}