LCA问题转RMQ问题
DFS整个树,每次进入某个节点都记录下来,就得到了一个2n-1长度的序列D(DFS序)。假设pos[i]表示节点i第一次出现在序列D中的次序,那么欧拉序列就是E[i]=pos[D[i]]。由于从节点u走到节点v的过程中必然经过LCA(u,v)且不会经过LCA(u,v)的父节点,所以节点u、v的LCA就是欧拉序列区间[pos[u], pos[v]]中最小节点(假设为w)所对应的D[w]。
Four Russian
四俄罗斯人算法就是一个分块ST表,将ST表的时间复杂度从O(nlogn)降到了O(nloglogn),只不过常数很大。就是把原数组分为长度为logn的块,将每个块的最值处理成一个ST表,将每个块内部的查询处理成单独的ST表,这样每次查询都可以分解成对不超过3个的ST表查询。
±1RMQ
对于欧拉序列,两个相邻的u和v不是u=v+1就是u=v-1。这里把分块长度改为logn/2,所以可以把每个块转化为logn/2-1长度的二进制序列,对于转化后的二进制序列不同的块称为本质不同的块,而本质相同的块查询结果是相同的。本质不同的块的数量为2^(logn/2)=sqrt(n),暴力处理所有本质不同的块的所有可能查询复杂度为sqrt(n)(logn)^2/4。
单调栈代替暴力求块内RMQ
对一个块内的序列运行单调栈算法,并且每次将每个元素入栈时的栈情况保存下来(因为块长度为logn/2,为节省空间可以使用状压),例如对于的序列1 3 5 2 4,存储的单调栈为00001,00010,00100,01100,10100。
对于块内最大值查询[L,R],只需要找到R时刻单调栈内第一个≥L的元素即可(不证明),写成位操作即为:L+_builtin_ctz(mst[R]>>(L-1))。
比如查询[2,4],首先找到单调栈mst[4]=01100,然后将其右移L-1位使其自然溢出为0110,再用_builtin_ctz计算末尾0的个数为1,最后加上L即为答案3(序号3而非数值3)。