双栈队列
众所周知,栈可以维护一系列满足满足结合律的信息,支持 (O(1)) 插入删除 以及 (O(1)) 对当前栈查询该信息,方法是在插入每个元素后,把新的该信息的一个副本入栈,当删除的时候就可以直接从栈顶弹出。这样可以维护一些不存在逆运算(或者逆运算复杂度特别高)的信息,比如min/max(gcd/lcm的本质是min/max),以及矩阵乘法等。
其实因为可以用两个栈实现一个队列,所以也可以用队列维护这些信息,在2019年暑假多校训练有一道题要求一个队列中所有矩阵的矩阵乘法的结果,我也是第一次从那里知道这个技巧。事实上lyd的书上面记载了这个技巧,应该可以默认银牌玩家们都会这个玩意。
示例:可以取队列中的最小值的双栈队列。
时间复杂度:所有方法都是(均摊) (O(1)) 。
空间复杂度:显然是 (O(n)) 。
struct Queue {
static const int MAXN = 1000000;
static const int INF = 1061109567;
int s1[MAXN + 5], s2[MAXN + 5];
int s1top, s2top, s1min;
void Clear() {
s1top = 0;
s2top = 0;
s2[0] = INF;
s1min = INF;
}
void Push(int x) {
s1[++s1top] = x;
s1min = min(s1min, x);
}
void Pop() {
if(s2top)
--s2top;
else {
while(s1top)
s2[++s2top] = min(s2[s2top - 1], s1[s1top--]);
--s2top;
s1min = INF;
}
}
int Size() {
return s1top + s2top;
}
int Min() {
return min(s2[s2top], s1min);
}
};