Qtree4
题意:
$n$个点,每个点有一个颜色,黑或白
每次查询最大白点间距离
带修改
$n=10^5,q=2*10^5$
(相信大家边分治,LCT等 $O(nlog^2n)$做法都会了)
但是这里有一个常数巨大的$O(nlogn)$做法
前置芝士
1.全局平衡二叉树(详见2007年论文Qtree问题解法的一些研究)
在一些静态树上查询,修改问题中,LCT能做到超大常数的$O(logn)$,而树链剖分只能做到$O(log^2n)$,原因何在?
因为LCT整棵树可以看做一个大的spaly$splay$,仍然可以进行势能分析
而树剖只能做到单条链最优(局部最优),但是全局并没有最优
全局平衡二叉树 就完成了把LCT强行静态的过程
轻重链剖分的部分是一样的,但是我们对每一条链建立一颗二叉搜索树
给每一个点一个权值为轻儿子$size$之和$+1$(自己),然后每次找重心递归建树
证明每个点的深度为$O(logn)$很简单,每次调到父亲子树大小(包括虚子树)至少翻倍
然后就可以开开心心的以一个$log$的做法做树剖题了
2.把任意一棵树转化为树上距离不变的二叉树
相信大家都学过边分治吧,那我就不讲了
直接上图
原树
二叉树
其中红点为新建的虚点,红边的边权均为0
对于每一个点,它的儿子都这样处理,然后就变成有$2n$个点的二叉树了感受一下,是不是很神奇?
正题开始
首先考虑最强的树上分治链分治
对于每一条链维护$lca$在这条链上的最大白点距离
直接做的做法:
以下为了方便,点$x$的轻子树和表示以$x$为根的子树去掉它的重子树,点$x$的轻子树表示以它的一个轻儿子为根的子树,$dfn$表示$dfs$序
对于每一个点$x$维护一个堆,记录$x$的每个轻子树内任意黑点到$x$的距离的最大值,
线段树维护答案
对于$dfn$区间$[l,r]$,记录三个值:
1.$lmax$:所有$dfn$为$[l,r]$点的轻子树和内的所有黑点到$dfn$为$l$的点的距离最大值
2.$rmax$:同理,表示所有$dfn$为$[l,r]$点的轻子树和内的所有黑点到$dfn$为$l$的点的距离最大值
3.$ans$:表示所有$dfn[lca]\in [l,r]$ 的黑点的距离最大值
区间合并:线段树上$x$的左儿子为$ls$,右儿子为$rs$
边界:点$x$对应区间$[L,L]$ $D_1=$堆内的最大值,$D_2=$堆内的次大值(来自两个不同轻子树)(若没有为$-\infty$)
若$x$为白点
(自己到自己,自己到最远的,最远的到次远的)
否则
然后我们发现其实距离堆内维护的就是每个轻儿子线段树顶的$lmax+dist(x,son)$
每条链的答案可以记在另一个堆里,询问时直接查即可
复杂度分析:
dist(i,j):发现总是在求祖先-后代距离,所以深度减一下$O(1)$
建树O(n)
每次修改$O(logn)$条链,每次线段树$O(logn)$,修改距离堆$O(logn)$,修改记答案的堆$O(logn)$总复杂度$O(nlog^2n)$
每次查询$O(1)$获取堆顶即可
总复杂度$O(qlog^2n+n)$
愚蠢的$log^2$做法到此结束
考虑降为一个$log$
首先直接上全局平衡二叉树可以把线段树部分降为单次询问$O(logn)$
答案堆直接不要了,全局平衡二叉树的$ans$带上轻子树和内的答案即可
然后是距离堆
我们发现距离堆内的点的个数为轻儿子个数
所以把它转成二叉树就不用堆来维护了
惊不惊喜,意不意外
然后就可以一个$log$愉快的过掉了
其实bb了这么一大堆,代码十分好写
码风丑,大佬轻喷
另外有一个细节,我的二叉查找树结合了线段树的特点,(有点像宗法树)
1 |
|
最后祝大家$rp$++