题意:
定义一条路径的权值为经过边边权的最大值
两点u,v的权值为f(u,v)等于uv之间所有简单路径的权值的最小值
两张图G1,G2,都有n个点G1点编号为 [ 1 , n ] [1,n] [1,n],G2编号为 [ n + 1 , n + n ] [n+1,n+n] [n+1,n+n]
求 ∑ u , v ∈ [ 1 , n ] f ( u , v ) ∗ f ( u + n , v + n ) \sum_{u,v\in [1,n]} f(u,v)*f(u+n,v+n) ∑u,v∈[1,n]f(u,v)∗f(u+n,v+n)
显然f(u,v)为最小生成树的路径最大值
考虑在uv之间的最大权边上统计uv的答案
可以用边分治,但我不怎么会打,有点麻烦
由于是最小生成树,考虑使用kruskal重构树,对两个图都建kruskal重构树
那么u,v的答案就会在lca处统计到
在第一个重构树中枚举lca,那么这个地方的权值只对左右两子树之间的答案有贡献,现在需要求左右两子树在另一个图中的答案,我们需要一种类似左右子树合并的做法来统计。
为了保持复杂度,我们需要使用一种较浅的结构来支持合并,这就想到了点分树,对另一个kruskal重构树建点分树,那么一开始,每一个点只存有在点分树中到根的路径,接着对于枚举的lca,将左右两点分树合并,顺便维护答案,点分树合并和线段树合并类似,如果对于两边子树有同一个点,那么这个点要往下走,合并下面的子树,否则只用保留其一。
那么现在的问题在于,点分树的两个子图的同一点,如何计算答案
重心父亲和重心儿子可能没有祖孙后代关系
如图,两条黑边走下去的重心,两块之间的答案就是方点,答案就是个数之积乘上该重心的权值,但是对于黑边和蓝边的答案是lca就是绿点,所以在储存点分树的时候要记下那条边是往上的,那么这条边的要记录下那一块点与方点的lca权值和,蓝边与黑边的答案就是该和乘上其他两个的大小。
时间复杂度 O ( n log n ) O(n \log n) O(nlogn)
事实上可以对kruskal的边赋权为点权的差分,将max变为权值和,再做点分树合并,更简单点。
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 200100
#define M 3800000
#define mo 998244353
using namespace std;
int s[N][3],son[N][2],n,m,top,ps[N+N],c,v[N],sz[M],sn[M][3],sm[M],Fa[N],siz[N],rt,hd,tl,que[N],fa[N],R[N],tot,ans,f[19][N+N]