记录一下近期收集到的没用的小 \(trick\) 。
并查集合并树
我们考虑去维护这样一种操作:
1 x y
给 \(x\) 和 \(y\) 之间连一条无向边。2 x
询问 \(x\) 所在的连通块内点的编号是否是连续的。
我们先用并查集跑一遍合并连通块的过程,同时将合并过程用一棵树表示出来。
具体的,对于每个连通块都开一个节点,当两个连通块合并的时候,让大连通块的节点向之前的两个连通块的节点连边。
叶子节点数是 \(n\),总节点数是 \(2n - 1\)。
然后对着新树跑 \(DFS\) ,并且对于每个叶子结点分配一个 \(DFN\) 序。
由于合并过程中的每一个连通块都可以被一个节点表示,所以其内部点的 \(DFN\) 序是连续的。
这个东西有着比较好的性质。
我们把所有点按 \(DFN\) 序排序,全过程中所有的连通块都可以被表示为这个序列的一个子区间。
这样,我们就把原问题改造成了序列上,询问区间内的数字是否连续。
很容易就做到了 \(O(n\ log n)\)。
当然,对于一般的问题,重标号能解决的用启发式合并都能解决。
有一些不能解决的,也可以用其它玄学算法做到相同的复杂度。
目前还没有找到这东西的用处。。。
丢一个能做的题 永无乡。
貌似这东西很像克鲁斯卡尔重构树来着。
归并连续段
考虑我们现在正在跑 CDQ。
左边有一些区间加,右边有一些区间查询,我们要统计贡献。
首先,如果这是一个静态的问题的话,显然可以直接差分,然后前缀,做到 \(O(n + m)\)。
但这是 CDQ 啊,如果单次合并复杂度带个 \(n\) 显然就废了。
于是我们考虑,如果操作只有 \(m\) 个,那么可以将原序列划分为 \(O(m)\) 个连续段。
这样的话做差分或者前缀复杂度就对了。
具体的,我们还需要开一个 \(O(n)\) 长度的桶记录修改,来避免二分查找。
但是还有一个问题,划分连续段需要排序,就又多了一个 \(log\)。
既然是 CDQ,那我们就可以进行归并。每次将左右两边的连续段归并作为新的连续段。
常数貌似很大,而且我没写过。
斜切坐标系
考虑这样一个问题:
算了懒得写题面了,丢一个 链接 跑路。
我们考虑如何正确的使用 kdt。
首先,kdt 的复杂度基于矩形查询。显然直接查曼哈顿距离复杂度不对。
虽然一般来说不好卡满。
到一个点曼哈顿距离相同的点在一个斜着的正方形上。
所以我们可以在坐标轴上画两个直线,\(y = x\) 和 \(y = -x\),分别作为横坐标和纵坐标,建立新的坐标系。
然后查询的时候就二分答案,然后矩形查询是否有点即可。
复杂度 \(O(m \sqrt n\ logn)\),应该不会有人去打这种东西吧。。。
可以进一步把结论推广到更高的维度,仍然是斜切坐标系。
复杂度 \(O(m \cdot n^{1 - \frac{1}{w}}\ log n)\),貌似也用处不大吧。。。。
不知道叫啥,就叫期望吧
期望的线性性本质上来讲其实就是乘法分配律。
从期望的定义出发来做个题吧。
你初始的时候站在 \(0\) 位置,接下来有 \(n\) 种操作。
第 \(i\) 种操作会让你有 \(p_i\) 的概率向前走一步,\(1 - p_i\) 的概率向后走一步,这种操作会执行 \(a_i\) 次。
现在对于 \(i \in [1, k]\),求执行完这 \(n\) 种操作之后你的坐标的 \(i\) 次方的期望。
\(n \le 10^4, k \le 20, a_i \le 10^{18}\)。
先考虑 \(i = 2\) 的情况。
\[\sum_{p} (p + 1) ^ 2 = \sum_{p} p ^ 2 + \sum_{p} 2 \times p + \sum_{p} 1 \]\(\sum_{p} (p + 1) ^ 2\) 表示向前走一步之后的坐标的平方的期望,\(\sum_{p} p ^ 2\) 表示之前的坐标平方的期望,以此类推。
于是我们发现这个东西的转移是线性的,可以用矩阵来刻画。
然后这就是个矩阵快速幂了。对于每一种 \(p_i\) 都可以写出来一个转移矩阵。
造矩阵的过程貌似需要一点二项式定理。
总感觉有不少想写的,但是想不起来了。
以后能想到啥再更新吧。