https://codeforces.com/contest/1902/problem/F
方法一
可以从树上路径想到轻重链剖分(也可以用其他种类的LCA算法),然后从数的异或表示很容易想到线性基。
然后因为是无修改的,所以可以轻重链剖分+ST表+线性基。具体来说就是:
先进行轻重链剖分。然后把每次在链上的区间查询接到ST表上,然后ST表中存储[L,R]下标范围的线性基。
然后ST表可以延迟初始化,毕竟在树上很多区间的结果其实是无用的,延迟初始化的方法是用个 inited 标记,然后查询ST的数据之前先dfs一次,如果没有被初始化则递归调用dfs进行初始化并打上 inited 标记。这个方法对其他版本的ST表没有太大作用因为其他版本的ST表的初始化是O(1)的。
初始化复杂度:轻重链剖分初始化O(n),ST表初始化O(n*logn)*合并复杂度,线性基合并复杂度O(B)。总体复杂度O(n + n*logn*B) = O(n*logn*B)
查询复杂度:q次查询,每次查询,轻重链剖分跳转 O(logn),ST表回答O(1) *合并复杂度,线性基合并复杂度O(B)。总体复杂度O(q*logn*B)
方法二
很显然倍增LCA算法也是可以的。注意倍增LCA的时候存储每个节点u向上跳2i步走到的父亲节点,同时也是向上跳2i步过程中覆盖到的所有的点。所以说
LB[u][0] 包含 a[u] 和 a[p] 两个数字
LB[u][i] = LB[u][i - 1] 和 LB[pa[u][i - 1][i - 1] 的结果
这里也需要一个小trick卡常数,就是求解路径上的所有点的线性基的时候,要先求出LCA的位置L点,然后再分别从X点和Y点直接跳到L点,这样只需要合并2轮,反之如果先把X点跳到和Y点同样的深度,再X点和Y点一起向上跳到L点的过程中合并线性基,则要合并3轮,事实证明这里的常数确实是偏大的。
上面两个方法的启发是,如果某个操作不是O(1)的,那么要想一些小trick来减少这个操作的次数,为此可以多做几轮O(1)的其他操作。对于第一个方法,浪费的O(1)的操作是 inited 标记和每次访问之前的dfs。对于第二个方法,浪费的O(1)操作是X点和Y点重复进行了求LCA的过程,具体来说是用 3次的跳跃操作(求X点和Y点的LCA=L点)O(logn)+2次把X/Y点提升到L点高度的跳跃操作O(logn)+2次线性基合并操作O(log^2n) 代替了 3次的跳跃操作(求X点和Y点的LCA=L点)O(logn)+3次线性基合并操作O(log^2n)。
初始化复杂度:倍增LCA初始化O(n*logn)*合并复杂度,线性基合并复杂度O(B)。总体复杂度O(n*logn*B)
查询复杂度:q次查询,每次查询,倍增LCA跳转 O(logn)*合并复杂度,线性基合并复杂度O(B)。总体复杂度O(q*logn*B)
方法三
上面的做法是硬套数据结构的解法。官方解法和jiangly的方法一样。
对于每个节点u,记录其到从根节点r的路径上,遇到的使得线性基数量+1的节点的深度。注意这里的路径是有方向的,因为做LCA的时候要往上跳,所以要记录在往上跳的过程中碰到的哪些使得线性基增加的节点,把他们合并入此次查询的线性基中。
说得很好听,但是怎么做呢?
假设已经计算出了节点u的父亲节点p的结果(一个线性基,其中插入的每行记录了插入点的深度),考虑如何从p转移到u。
很明显,可以先把u节点的权值加入线性基,然后把父亲节点p中的结果从深度最大的插入,直到深度最小的。(选择排序)
需要注意的是经典版本的线性基写法中,是个上半阶梯矩阵(也就是说每一行的最高位对至少比上一行偏右1位(下降1位))但并不代表线性基中的数字一定在集合中出现,同时深度也不能保证。
jiangly的写法是将父亲节点p的结果复制,然后把u节点的权值加入,遇到了某一行已经被占领的话,则用u这一行代替此行(设带他来的节点为v),然后把v的这一行的结果继续往下插入,相当于就是把每一行往下挤一下。这个方法很巧妙,把O(B^2)的选择排序换成了O(B)的插入排序。
复杂度 O(n*B) 然后就得到了每个节点u,记录其到从根节点r的路径上,遇到的使得线性基数量+1的节点的深度。
下一步,对每次查询的x点和y点做LCA,求出LCA的深度dep[L],复杂度O(logn)。然后把点x和点y的线性基中,>=深度dep[L]的行合并到一个新的线性基中,复杂度O(B),这个线性基就不带有比L还高的点的信息了。
初始化复杂度: O(n*B)
查询复杂度:单次O(logn+B),总共q次。
这是一个带有额外信息的线性基,然后提供了一种幺半群的维护思路,也就是从每个节点往上进行思考,从父节点转移,用新节点的数据插入父节点的数据中,淘汰掉父节点中旧的数据。
- 题解 Codeforces Queries Trees Again题解codeforces queries trees codeforces queries 1902f again 题解codeforces queries 1902f 题解codeforces queries 825g codeforces segments 1858d trees codeforces corridor again round codeforces queries median 1526f codeforces queries exotic 1864f codeforces queries round 859 题解acboy needs again