题目链接:
题目大意:给出一棵$n$个节点的树,要求给每个点赋一个$1\sim n$之内的权值使所有点的权值是$1\sim n$的一个排列,定义一条边的权值为两端点权值差的绝对值,要求对于任意两点间的路径要么路径上所有点的点权单调,要么存在路径上的第三个点到这两个点的路径分别单调(即两点间路径先单调递增再单调递减或先单调递减再单调递增)。求出整棵树最小边权和,并支持动态插入点之后完成上述问题。
前言:
这道题综合性比较强且代码量及细节非常多,是迄今为止我做过最神仙的题(没有之一)。题目大致可分成贪心、树形DP、树链剖分、TopTree、及链分治五部分,我们分步讲解。
贪心:
1、题目中对任意两点路径的要求可以转化为“存在一个点到所有点的路径都单调”。
这个可以用反证法证明:
如果上述结论不符,那么存在一个点$x$到一个叶子节点$z$的路径上有题目中所述的第三个节点$y$,假设$x$到$y$单调递减,$y$到$z$单调递增。我们以$x$为根,那么除$y,z$所在子树之外的其他$x$的子树中的点到$x$必须要单调递减,否则这个点$->x->y->z$的路径被分成了单调的三段。我们再讨论$x->y$路径上的点及他们的子树,这些点到$y$必须也要单调递减,否则这些点到$z$的路径也被分成了三段。然后讨论$y$到$z$路径上的点及他们子树中的点(不包括$y$其他子树中的点),这些点到$y$的路径要单调递减,否则他们到$x$的路径被分成了三段。至于$y$其他子树中的点到$y$可以单调递增也可以单调递减。这样所有点到$y$的路径就都是单调的了,所以上述结论成立。
这样,我们以点$y$为根,那么有一部分子树是单调递增的(即一个节点的点权小于每个子节点的点权,下同理),另一部分是单调递减的,这也就可以将整棵树看作是共用堆顶的一个大根堆和一个小根堆(并不是二叉堆)。我们先来考虑一个堆的情况,以小根堆为例。
考虑堆中的一个子树,它的值域为$[l,r]$(即子树中最小点权与最大点权),那么将它的值域范围减小一定会使这棵子树内部的答案减小,假设将值域范围减小了$d$,那么子树内部的答案至少会减小$d$。现在考虑互不包含的两棵子树$T1,T2$,假设$T1$的值域为$[l1,r1]$,$T2$的值域为$[l2,r2]$,且$l1<l2<r1<r2$,那么显然权值在$[l2,r1]$值域范围内的点一定有$T1$中点的点权大于$T2$中点的点权。现在我们将点权在$[l2,r1]$范围内的点重新分配,使得分配后的$r1<l2$,显然两棵子树的内部答案都会减小。这就启示我们每棵子树中的点权值域要连续。
2、对于一个堆,必然存在一种最优策略使得每棵子树中点的点权值域连续
这个也很好证明,假设有一棵子树的点权值域不连续,那么一定有另一棵子树与这棵子树的值域有交集,将交集消除显然会使两棵子树的答案更优,因此每棵子树内的点权值域必然连续。
那么一棵子树的答案就可以看作是每个点与它所有子节点之间的边权和之和。假设一个父节点$u$的点权为$x$,那么每棵子树的值域就是$[x+1,x+size1],[x+size1+1,x+size1+size2]……$(其中$size[i]$表示第$i$棵子树的大小),显然$u$的每个子节点点权是以他们为根的子树中最小的点权,即$x+1,x+size1+1,x+size1+size2+1……$,$u$与这些子节点之间的边权和就是$1+(size1+1)+(size1+size2+1)……$。可以发现每个子节点的子树大小会影响后面所有子节点与$u$之间边的边权,所以应该贪心地将$size$小的子树排在前面。我们将所有子树按子树大小从大到小排序,假设一棵子树的排名为$p_{i}$,那么$u$与这些子节点之间的边的边权和就是$\sum\limits_{i}^{ }size_{i}(p_{i}-1)+1$。
那么现在再来考虑共用堆顶的这两个堆,即根节点与其子节点之间边的贡献,如果只有大根堆或者小根堆那么边权和还是上面那个式子。这也就是说每个点的子树大小还要影响后面所有子节点到根的边的贡献。而如果我们将这些子树按大小顺序交错分给大根堆和小根堆,那么决策显然是最优的,每个子节点的子树大小只会影响后面一半子节点的贡献,即代价为$\sum\limits_{i}^{ }size_{i}\left \lfloor \frac{p_{i}-1}{2}\right \rfloor+1$。
树形DP:
有了上面的贪心结论,就可以解决静态树的答案了。我们将每个点的出边指向的子节点按子树大小从大到小排序。对于每条有向边(将无向边看作两条有向边)维护有向边指向点$x$的子树中所有边的贡献,这一步通过两次树形DP即可实现,具体实现参见代码。然后枚举每