这种优化只能对于在扩展缩小区间维护答案时,查询的东西是可以差分的,并且只能优化掉修改的复杂度;
比如你在查一个区间的逆序对,当你扩展右端点时,你需要将答案加上前面这段区间中比新的右端点位置上的值大的个数,这种查询就是可以差分的,比如我们当前的区间的左右端点为(L,R),那么我们扩展右端点就可以先查([1,R])中比(R+1)这个位置上的数大的个数减去([1,L-1])中比(R+1)位置上的数大的个数;
然后对于这种类型的莫队,他的修改复杂度很大时,因为我们最多要修改((n+m)*sqrt n)次,所以根本接受不了;这个时候考虑再次把这((n+m)*sqrt n)次修改的询问离线下来并且差分,这样只需要对着序列扫一遍,修改(n)次就可以了,但是你查肯定还是要查((n+m)*sqrt n)次;
但是往往空间可能会比较吃紧,毕竟有((n+m)*sqrt n)次修改的查询,再次考虑莫队移动区间的性质:它每次移动的都是一段连续的区间;我们还是考虑移动右端点,此时的区间是(L,R),我们要把右端点移动到(R+K)这个位置上;
可以发现(R+1)到(R+K)这段位置他们差分后的查询都有一个减去([1,L-1])的贡献,然后另一半都是减去([1,扩展出的位置-1])的贡献;那么我们直接把(R+1)到(R+K)这段区间直接离线到(L-1)这个位置上去;然后对于后面那种,我们可以维护一个这样的东西(F[i]=[1,i-1]对i的贡献),然后求个前缀和,这样空间就被优化成了线性的;动左端点同理,也是这么去干,去推一下离线到哪就行了;但是前一个把区间离线到对应节点上去,还是要枚举区间那么长一个个去查询,所以还是得查询((n+m)*sqrt n)次;
最终我们莫队的复杂度由原来的(O((n+m)*sqrt n *(修改复杂度+查询复杂度)))变成了现在的(O(n*修改复杂度+(n+m)*sqrt n *查询复杂度)),这样我们就把每次莫队扩展所变化的值预处理好了,每次扩展缩小区间(O(1))修改;
这个思想来自于LuoguP4487;LXL大毒瘤
做了这题然后没几天就在CodePlus三月的月赛上用到了,优化了一个log的复杂度下来成功用假算法a了个题;