baka's trick

发布时间 2023-10-04 17:25:31作者: ImALAS

baka trick 之于双指针,就像回滚莫队之于莫队。

考虑将双指针的过程变换一下:加入一个分界点 \(mid\),分别维护 \([l,mid],(mid,r]\) 的信息,当 \(l>mid\) 的时候 \(mid\gets r\),然后把原先 \((mid,r]\) 的信息直接拿过来用,原来存储 \((mid,r]\) 信息的容器清空。

不难发现一个信息只会被加入 2 次,所以时间复杂度 \(\mathcal O(nw)\)\(\mathcal O(w)\) 是单次信息加入的复杂度。这个过程可以用双栈模拟。也就是每个栈维护栈底到栈顶信息的前缀和,当左边栈空的时候把右边栈里的元素加入左栈。

例题 I. [2019 五校联考镇海 B] 小 ω 的仙人掌

求最短区间 \([l,r]\) 使得做完 \([l,r]\) 内的背包后权值为 \(w\) 的代价 \(\le v\)\(n\le 10^4,w\le 5000,v\le 10^9\)

场上不会这个 trick 被打爆了 /ll,不过分治卡卡常好像跑得飞快?

这个背包的本质是 \(\min,+\) 卷积所以没法删除,于是使用双栈优化即可。\(\mathcal O(nw)\)

例题 II. [雅礼集训 2018 Day 10] 贪玩蓝月

这题并不是 baka trick /lh,但我确实没题放了 /ll。

线段树分治是 trivial 的,但是不牛。

还是考虑双栈模拟,左栈存队列左端,右栈存队列右端,求答案就做一个单调队列滑动窗口。为了代码方便可以把其中一个背包复制一遍,写起来比较舒服。

当一个栈弹空的时候,暴力重构两个栈,也就是把另一个栈的一半信息分过来。

这样做的复杂度如何?考虑势能分析。令势能为两栈大小之差的绝对值,每次增删会产生 \(1\) 的势能,而每次重构会花费 \(\mathcal O(np)\) 的代价消耗 \(n\) 单位的势能。所以复杂度即为 \(\mathcal O(mp)\)

以后有例题了可能会再放?