数据结构维护技巧(长期更新)
拜谢lxl
维护函数复合
大概是每个位置上有一个函数\(f(x)\),给出\([L,R]\)和初值\(v\),算\(f_R(f_{R-1}(\dots f_L(v)\dots))\)。
有个东西叫插入-标记-回收算法。
首先将所有询问离线,然后拿扫描线扫一遍序列。维护一个集合\(S\),存每个询问的结果。
-
插入:扫到\(i\)后,如果这个地方是某个询问的起始位置,那么久把这个询问加入\(S\)。
-
标记:从\(i-1\)到\(i\),对\(S\)中所有询问的影响是一样的,通常在\(S\)上打标记实现。
-
回收:存在以\(i\)为右端点的询问,那么需要从\(S\)中取出以\(i\)为右端点的询问的答案。通常需要记录一下询问\(x\)在\(S\)中的位置以实现快速查询。
I.QOJ # 8672. 排队
每个位置上有个函数\(f(x)=x+[x\in [l_i,r_i]]\),每次同上询问\([L,R]\),初值为\(0\)。
Sol:
会上面那个东西就很简单了。在每个询问开头和结尾处记录一下。拿扫描线扫这个序列,遇到一个询问就插入。用一个FHQ-Treap维护\(S\),每次插入就是向FHQ中插入一个值为\(0\)的点,打标记就是从FHQ中分裂出值在\([l_i,r_i]\)的点,然后整体加\(1\)。可以发现整体加一后仍然满足左树小于或等于右树,所以区间无交,正常合并即可。
插入一个点后存一下这个询问对应的点的编号,询问的时候直接找到那个点,然后暴力下传根到这个点路径上的标记,再查询其值。因为FHQ的树高保证了\(O(\log n)\),一共\(q\)次,所以这部分是对的。然后就做完了。