Here I will describe a way to maintain deque that will allow us to find the smallest element in deque at any time. Maybe this technique is well-known, but I couldn’t find any info about it, so decided to post it there.
Minimum Stack and Minimum Queue
First, we want to maintain stack with the ability to find its smallest element whenever we want. Let's store minimums on the corresponding prefix of stack along with elements. This way we can easily push/pop elements and find minimum in $$$O(1)$$$.
Minimum Queue can be maintained using two Minimum Stacks: one stack will store some elements from beginning, and the other from the end. We will push elements to the second stack and pop them from the first. If the first stack becomes empty, then we move all elements from the second stack into the first. It will work in $$$O(N)$$$ amortized.
Minimum Deque
Actually, we can maintain Minimum Deque the same way we maintain Minimum Queue, but it will be too slow. The problem is the number of moved elements: in the worst case we will move all elements every operation by removing first and last element alternately. So instead of moving all elements let's move only a half of them at a time. Turns out it works in $$$O(N)$$$!
But how to prove it? Let $$$k_i$$$ be the number of elements deque contained right before $$$i_{th}$$$ operation, the algorithm above obviously works in $$$O(N + \sum k_i)$$$. Also $$$k_i = \frac{k_{i-1}}{2} + q_i$$$, where $$$q_i$$$ is the number of elements added between operations $$$i-1$$$ and $$$i$$$. We can see that $$$q_i$$$ contributes $$$q_i$$$ to $$$k_i$$$, $$$\frac{q_i}{2}$$$ to $$$k_{i+1}$$$, $$$\frac{q_i}{4}$$$ to $$$k_{i+2}$$$ and so on. It follows that $$$q_i$$$ contributes $$$O(q_i)$$$ to $$$O(\sum k_i)$$$. $$$\sum q_i$$$ is obviously $$$\leq N$$$, so $$$O(\sum k_i) = O(N)$$$. That's why the algorithm above is $$$O(N)$$$ amortized.
iirc this is well known in Japan and it is called SWAG (Sliding Window AGgregation). it's a pretty cool name I think
Aha, it can solve problems with the two pointers trick. Because the two pointers trick needs to remove $$$value(left)$$$, and so it can help to remove while maintaining $$$\min{value}$$$. I once saw it in a contest's tutorial (not on CodeForces), but I didn't think about it carefully, though.
Is it different from priority_queue ?
Did you read article?
Yes, but unlike the priority queue, when you delete an element in a minimum deque, you can delete the first element or the last one, when in the priority queue you can only delete the smallest one, in the priority queue you lose that order of the elements.
this is well known in Croatia and it is called Monotnic Deque
I think monotonic queue is a different thing? Doesn't monotonic queue throw out unnecessary elements? I think it does if I am not mistaken
And where did I mention monotonic queue :P
Oh yes I guess I am mistaken :facepalm: I think I was just thinking about another technique with a similar name
Anyways, it should be well known in various countries with various names.
This is well known in Romania. I don't think it has a specific name.
i didn't know it ☹️
A seemingly easier argument: Consider $$$\operatorname{abs}((\mathrm{the\ size\ of\ the\ first\ queue}) - (\mathrm{the\ size\ of\ second\ queue}))$$$ as the potential function. push/pop front/back increases the potential by at most 1, and the rebalance zeroes the potential function.
Also, as a historical note, this structure appeared first in Hoogerwoord's A symmetric set of efficient list operations in 1992. I learned this fact in Exercise 5.1 of Okasaki's Purely Functional Data Structure.
doesn't rebalance make it zero?
oh yeah, you are right
One problem that require this ds RMI 2020 — Peru. The naive $$$O(nlogn)$$$ TLEs (time limit is $$$200ms$$$).
I think the best name I have heard for this technique came from rainboy who called it "stabbing points."
I was curious about how the constant factors look like, this is what I got. Cost is the average of add and remove operation. I only count the monoid operations:
Proof of last one: add/remove add 1 to potential (using the potential by ppavic), adding to the stack costs 1 by itself. 1 potential is 1 op when rebalancing.
The point is constant factor isn’t so bad so it could be used with less discretion.
Update: I realised the above analysis doesn't take account for the fact that you cannot perfectly rebalance if size is odd. Upto 1 op per removal is necessary depending on implementation.
See 2026F - Bermart Ice Cream for a problem that this trick could solve.