ST03Day3 可持久化

正题

      可持久化线段树写了太多遍了,回去主要练习的就是可持久化并查集,可持久化非旋treap,可持久化左偏树(可并堆),k短路以及一系列k小的题目。

      板子就不说了。

      可持久化并查集是基于可持久化数组的,可持久化数组可以直接使用可持久化线段树来维护,所以在按秩合并的情况下加一个log就可以。

       mex · 改

      先考虑离线的时候怎么做,按右端点排序,线段树维护每个权值出现的最大位置和最大位置的最小值,然后在线段树上二分即可。在线直接考虑可持久化即可,时空复杂度n log n

      UOJ14 DZY Loves Graph

      可持久化并查集回去可以写一写,大概就是把版本树建出来然后跳就可以,时间复杂度两个log。

      但也有更简单的方法,因为不会撤销一个撤销,删除k条边的时候,如果下一个操作不是撤销,那么就直接回退k条边,否则直接回答k级父亲的答案。

      BZOJ2653 middle

      中位数有个套路就是二分mid,然后将>=mid的值设为1,<mid的值设为-1,一个区间的和>=0那么中位数就>=mid,所以我们可以对于mid来建主席树,总修改点数不超过n个,然后维护一个最大前缀和最大后缀就可以完成操作,时间复杂度两个log。

      WC2016 鏖战表达式

      感觉没打过可持久化treap这题也不可能会,回去写一写吧,这里讲没什么用。

      BZOJ4504 K个串

      先想想第一大区间怎么做,每一个右端点维护一下当左端点为i的时候的权值,因为要去重,所以就给(las[i],i]加就好。

      推广到k大,发现这些线段树可以可持久化,而且时间复杂度只有一个log,具体证明可以考虑线段树在每一层最多有4个节点。

      那么每一次在该线段树上找次大就相当于先把最大的标记为负无穷然后再找最大。

      另一种做法不用改为负无穷就是每一次将当前区间最多裂为两部分然后在两边找最大,加入线段树,时间也是一个log,任君选择。

      USACO16DEC

      先把一个集合内的元素排序后差分,考虑一个方案肯定是由第i个集合第a_i小元素这样表示出来的。

      考虑最小堆,对堆中每一个元素都建一棵可持久化线段树,表示下一个选的元素增加值,当前将最小的取出来有两种拓展方案:

      1.在线段树中取最小的,将那个位置+1

      2.回退一步,将上一次取的位置标为正无穷,然后再找最小来取。

      相当于现在在B,A是B的上一个状态,而B是A能拓展的下一步的最小状态,那么我们将A能拓展到的所有状态分为两类,一类是B能到达的,一类是B不能到达的,那么显然第一种就是在拓展B,第二种就是先退回A,然后强行不走B,封死B取的位置,这样就可以保证和B没有交集。

      k短路

      这是一个非常经典的问题,以前的我只会nk,今天听了两种做法,受益匪浅,第一种就是a*,大概就是先反向跑出最短路径长度,作为预估值,维护一个小根堆就可以,取出最小值然后对其进行增广,然后将值加入堆。

      第二种可以考虑先把最短路树跑出来,一个非树边的有序序列就表示了一种路径,那么我们在最短路树上建一个可持久化可并堆,维护该点能通过树边到达的所有非树边。

       扩展的方式有两种,一种是在后面加入一条最小的边,一种是撤销一次操作,再加入一条最小的边。

      加入一条最小的边我们可以直接找当前结束点的对应可并堆的最小值,然后直接取,第二种就是用可持久化可并堆来把根弹出去,再取最小值。回去一定要写一写(flag n

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/108052300