P7447 [Ynoi2007] rgxsxrs 题解
可能更好的阅读体验
特别劝退的一道题目。
调了整整两天,码长 4.39kb -> 6.89kb
这道毒瘤题不仅卡时间,还卡空间。
题意
给定一个长为
1 l r x:表示将区间
2 l r:表示询问区间
思路
一看到题以为是类似第二分块的做法,后来发现了强制在线和巨大的值域范围。
首先看到要维护的值有和,最小值,最大值,可以想到可能可以用线段树维护。
但又由于这是
考虑对于值域进行分块。
由于值域有
具体来说,就是将值域分成
在每个块内维护一颗动态开点线段树,以在原序列中的位置为下标,如果在减的过程中,值域不在这一块,则暴力删除修改。
如何进行修改。
-
若此时节点最大值小于等于
x ,则可直接退出。 -
若此时节点最小值大于
x ,同样可以直接打上标记然后退出。 -
若都没有,则继续递归不断处理。
查询则可以直接像普通线段树一样查询。
考虑修改块的复杂度,每一个数最多改变
在考虑查询和修改的复杂度,由于就是普通的在线段树上的操作,所以复杂度同样为
这样的代码,你会获得
你会发现你
算一下空间,你就发现这道题居然也卡了空间。
考虑一个以时间换空间优化线段树空间的方法。
可以发现,线段树最下面几层的节点,占据了大量空间,考虑把底层换为分块来解决。
每次遍历到叶子节点的块时,直接暴力操作。
这样虽然时间效率变低了,但空间就被大量优化。
底层分块的实现可以尝试使用链表来维护,算一种常数小也比较好写的方法。
-
插入一个数时,直接接在此时的末尾的后面,复杂度
O(1) 。 -
删除一个数,同样是链表的基础操作,复杂度
O(1) 。 -
在做减法操作,下穿标记等操作时,只能遍历整个链表,复杂度
O(len) ,其中len 为链表长度。
这个玩意总得复杂度可能不怎么好算,但感觉也不会太慢。
实测,底层块长开
Code