先前还以为莫队算法是一个高级的东西。
可是仔细学习了一下,才发现这东西应该叫做——
一个优雅的暴力
对于一个询问区间[l,r],如果我们可以O(1)的得到区间[l,r-1],[l,r+1],[l-1,r],[l+1,r]的答案,那么从这个询问转移到另一个询问的时间复杂度为O(|l-l’|+|r-r’|)。
那我们可以确定一个解决询问的顺序,从而使复杂度达到O(n^1.5)
我们把每个询问看做二位平面上的一个点,那么如果我们对这个东西做最小生成树,那么沿着树边做一定是最优解。
不管你会不会,反正我不会。
但是,如果莫队算法这么复杂的话,它也不会这么普及。
这个算法有一个优雅的替代品——分块(分块大法好)。
我们把所有的询问排序,第一关键字为左端点所在块的编号,第二关键字为右端点的编号。
为什么这样做也是O(n^1.5)的呢?
考虑i和i+1,若它们在同一块里,那么r最多增加n。单调递增,这样的东西最多有n^0.5个,所以复杂度为O(n^1.5)。
若它们在不同的块,那么r的变化也是n。这样的东西也有n^0.5个,所以也是O(n^1.5)
那么总的复杂度就是O(n^1.5)
Code
pl=1;
fo(i,1,m) {
if (pr<ask[i].r) fo(j,pr+1,ask[i].r) updata(j,1);
else fo(j,ask[i].r+1,pr) updata(j,-1);
if (pl<ask[i].l) fo(j,pl,ask[i].l-1) updata(j,-1);
else fo(j,ask[i].l,pl-1) updata(j,1);
pr=ask[i].r;pl=ask[i].l;
}
updata视情况而定。
带修改?
那么把排序的关键字改成三维就好了。
具体请看a_crazy_czy的blog