Stack and queue (including monotone stack and monotone queue)

Time:2022-1-18

Stack

Algorithm idea

Stack(\(stack\))Also known as stack, it is a linear table with limited operation. Limit linear tables to insert and delete only at the end of the table. This end is called the top of the stack, and the other end is called the bottom of the stack. Inserting a new element into a stack is also called stack entry, stack entry or stack pressing. It puts the new element above the top element of the stack to make it a new top element; Deleting an element from a stack is also called out of stack or out of stack. It deletes the top element of the stack and makes its adjacent elements become new top elements—- From Baidu Encyclopedia

附图

It can be seen from the above data that the stack is a “first in and last out” data structure. It is a data structure that can only be inserted and deleted at the top of the stack. As shown in the figure, it supports stacking(\(push\))And out of the stack(\(pop\))There are two operations. Because you can only enter the stack from one end and exit the stack from the other end, any element, as shown in the figure above\(s_2\), you have to stack after it\(s_3\sim s_n\)\(s_n\)Namely\(s_{top}\))In other words, the advanced elements must wait until the later elements are out of the stack. Therefore, the stack is called “first in and then out”(\(FILO\))Table.

code snippet

Enter the stack

It’s very simple to enter the stack. You just need to move the top of the stack one grid, and then put elements in a new grid.

void push(int x){
  s[++top]=x;
}

Out of stack

It is also very simple to get out of the stack. You only need to move the top of the stack down one grid, and there is no need to replace it, because if an element needs to occupy this grid into the stack, it will be replaced.

void pop(){
  top--;
}

Examples

P1739Expression bracket matching

Carelessness

Given a\(@\)Determine whether the parentheses (only “(” and “)”) match.
‘(() ())’, ‘(())’, but ‘())’, ‘() ()’, do not match.

thinking

It is obviously impossible to judge only the number of left and right parentheses, because there are a lot of data that are obviously unacceptable, such as “) () (“, “()) (()”, etc.
So, at this time, we will use the stack. Read the expressions one by one. If it is “(“, it will be put on the stack (obviously, the stack should be\(char\)Type), if it is “)”, it is judged that if the stack top is empty or “)”, it is not “(“, indicating that the right semicircle bracket does not match the left semicircle bracket at this time, indicating that it does not match. In addition, if the last stack top is not empty\(0\), indicating that the remaining parentheses are not matched, which is also illegal.

code
#include
#include
#include
using namespace std;
char a[260],s[260];
int top=0;
int main(){
	cin>>a;
	for(int i=0;i

P1449Suffix expression evaluation

popularization of science

Inverse Polish(\(Reverse Polish notation\)\(RPN\), or inverse Polish notation), also known as suffix expression (write operator after operand).
An expression\(E\)The suffix form of can be defined as follows:
(1) If\(E\)Is a variable or constant, then the suffix of E is\(E\)Itself.
(2) If\(E\)yes\(E1 op E2\)Formal expression, here\(op\)Is any binary operator, the suffix of E is\(E1’E2′ op\), here\(E1’\)and\(E2’\)Respectively\(E1\)and\(E2\)Suffix of.
(3) If\(E\)yes\((E1)\)Form, then\(E1\)The suffix is\(E\)Suffix of.
We usually write\(a+b\), this is an infix expression written as a suffix expression:\(ab+\)
\((a+b)*c-(a+b)/e\)The suffix expression for is:
\((a+b)*c-(a+b)/e\)
\(((a+b)*c)((a+b)/e)-\)
\(((a+b)c*)((a+b)e/)-\)
\((ab+c*)(ab+e/)-\)
\(ab+c*ab+e/-\)

The above example is explained here with a tree:
First, we build the tree of the above expression so that the middle order traversal of the tree is an expression (because we write infix expression. If we want to change the prefix expression, that is, Polish expression, into a tree, we need to build a tree so that its front order traversal is an expression). Then, the back order traversal of the tree is inverse Polish expression.

Carelessness

Give the suffix expression and output its value.

thinking

Read the suffix expression one by one, enter the stack when encountering numbers, calculate the elements at the top of the stack and the last bit after the top of the stack when encountering symbols, and finally output the top of the stack.

code
#include
#include
#include
using namespace std;
int s[260],top=1;
char x;
int main(){
	while(x!='@'){
		x=getchar();
		if(x=='.'){
			top++;
		}else{
			if(x>='0'&&x<='9'){
				s[top]=s[top]*10+(x-'0');
			}
			if(x=='+'){
				top--;
				s[top-1]+=s[top];
				s[top]=0;
			}else if(x=='-'){
				top--;
				s[top-1]-=s[top];
				s[top]=0;
			}else if(x=='*'){
				top--;
				s[top-1]*=s[top];
				s[top]=0;
			}else if(x=='/'){
				top--;
				s[top-1]/=s[top];
				s[top]=0;
			}else if(x=='@'){
				break;
			}
		}
	}
	cout<

queue

Algorithm idea

Stack is a data structure with one end in and out. Correspondingly, queue is a data structure with one end in and the other end out.

Queue is a special linear table, which only allows deletion at the front of the table and insertion at the back of the table. Like stack, queue is a linear table with limited operation. The end that performs the insertion operation is called the tail of the queue, and the end that performs the deletion operation is called the head of the queue—— From Baidu Encyclopedia


Similar to the stack, I won’t repeat it.

Monotone stack

Algorithm idea

As the name suggests, a monotone stack is a stack in which the elements in the stack have monotonicity. In other words, we put the elements in the sequence on the stack and make the elements in the stack monotonically increase or decrease. Maintaining such a stack is also very simple (the following assumption is to maintain a monotonically increasing monotonic stack). We will use the elements in the stack\(s_i\)Expressed as a sequence\(a\)The subscript of the element in, that is, when you see an element in the stack\(x\)When, it representsnonumber\(x\), butexpress\(a\)Elements in array\(a_x\), this requires special attention. When entering the stack, if the value represented by the top element of the stack is greater than the added value (i.e\(a_{s_{top}}>a_x\)\(x\)Indicates the added element, obviously\(a\)The element in the array (subscript), then\(top–\)That is, kick the top of the stack out. Because it’s added\(x\), i.e. representative\(a_x\), which is smaller than the top of the stack, and we want to maintain a monotonically increasing stack, so if\(x\)Adding directly will destroy the monotonicity, so it is necessary to push the stack out of the stack. Wait until all are kicked out of the top of the stack\(top\)After being kicked out (i.e. now the top of the stack)\(top\)accord with\(a_{s_{top}}), you can\(x\)It’s on the stack.
So, what does monotone stack do? Obviously, you can maintain a monotonically increasing stack. By putting the elements in the stack sequence one by one, you can find the length of\(n\)Sequence of\(a\)Front in\(k\)Minimum of elements(\(0)。 Because the stack is monotonically increasing, it is added in order\(k\)After two elements, the top of the stack must be the front\(k\)The minimum number of. However, you can obviously solve this very basic problem without monotone stack. One of the main functions of monotone stack is to find the first number larger (or smaller) than it on the right (or left) side of each number in the sequence (see example 1 for details).

Examples

P5788[template] monotonic stack&P2947 [USACO09MAR]Look Up S

Carelessness

Find the right side of each number in the sequencefirstA number larger than it.

thinking

Maintain a monotonically decreasing stack, then for each element, the element that makes it kicked out must be the first element larger than it. (I suggest you draw your own picture and analyze it carefully).

code
#include
#include
#define maxn 100005
using namespace std;
int n,a[maxn];
int s[maxn],top=0;
int ans[maxn];
void push(int x){
	while(a[s[top]]0){
		ans[s[top]]=x;
		top--;
	}
	s[++top]=x;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	s[++top]=1;
	for(int i=2;i<=n;i++){
		push(i);
	}
	for(int i=1;i<=n;i++){
		printf("%d ",ans[i]);
	}
	return 0;
}

P1901transmitting station

Carelessness

have\(n\)There are four launch stations, and each launch station has a height\(h_i\)And energy value\(v_i\), for each launch station\(i\), the first higher transmitting station on its left and right can receive its signal (i.e. cumulative value plus\(v_i\)), find the maximum value of the total accumulated energy value of each signal tower.

thinking

The two questions above are just to be added twice.

code
#include
#include
#include
#define maxn 1000005
using namespace std;
int n,a[maxn],v[maxn];
int s[maxn],top=0;
int ans[maxn];
void push(int x){
	while(a[s[top]]0){
		ans[x]+=v[s[top]];
		top--;
	}
	s[++top]=x;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i],&v[i]);
	}
	s[++top]=1;
	for(int i=2;i<=n;i++){
		push(i);
	}
	memset(s,0,sizeof(s));
	top=0;
	s[++top]=n;
	for(int i=n-1;i>=1;i--){
		push(i);
	}
	int mmax=-1;
	for(int i=1;i<=n;i++){
		mmax=max(mmax,ans[i]);
	}
	printf("%d ",mmax);
	return 0;
}

P2422Good feeling

Carelessness

There is a long for\(n\)Sequence of\(a\), define an interval\([l,r]\)Value of\(comfort_{l,r} = \min\limits_{i=l}^{r}{a_i} \times \sum\limits_{i=l}^{r}{a_i}\), please\(max(comfort_{i,j})(0 < i\le j\le n)\)

thinking

It is conceivable that enumerating each interval takes a lot of time, which is likely to make us\(TLE\)。 We might as well enumerate\(min(i,j)\)Obviously, we just need to enumerate\(n\)Times, because we can from\(1\)reach\(n\)enumeration\(i\), calculated in\(a_i\)Is the maximum in the interval of the minimum value\(comfort_{l,r}\)Because\(a_i \ge 1\)Therefore, we just need to make the interval as large as possible, so the interval we need to enumerate is from\(a_i\)At the beginning, the left and right sides are extended to the nearest two positions smaller than it (excluding these two values smaller than it) (so as to ensure that there is no less than\(a_i\)Number of, i.e\(a_i\)Is the minimum value in the interval and the interval is the maximum), and all values are calculated\(a_i\)Sum and multiplication of calculated intervals\(a_i\)(i.e\(a_i\)Is the maximum of the minimum\(comfort\)Value) is the maximum value.

code
#include
#include
#include
#define maxn 100005
using namespace std;
int n,a[maxn];
long long pre[maxn];
int le[maxn],ri[maxn];
int s[maxn],top=0;
void pushr(int x){
	while(a[s[top]]>a[x]&&top>=0){
		ri[s[top]]=x;
		top--;
	}
	s[++top]=x;
}
void pushl(int x){
	while(a[s[top]]>a[x]&&top>=0){
		le[s[top]]=x;
		top--;
	}
	s[++top]=x;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pre[i]=pre[i-1]+a[i];
	}
	s[++top]=1;
	for(int i=2;i<=n;i++){
		pushr(i);
	}
	memset(s,0,sizeof(s));
	top=0;
	s[++top]=n;
	for(int i=n-1;i>=1;i--){
		pushl(i);
	}
	for(int i=1;i<=n;i++){
		ri[i]=ri[i]==0?n+1:ri[i];
	}
	long long ans=-1;
	for(int i=1;i<=n;i++){
		ans=max(ans,(long long)(a[i]*(pre[ri[i]-1]-pre[le[i]])));
	}
	printf("%lld",ans);
	return 0;
}

Monotone queue

Algorithm idea

As we just mentioned, the monotone stack can calculate the top of a set of data\(k\)How to calculate any continuous value in a group of data (although it is easier to understand without monotone stack)\(k\)What is the maximum value of the data(\(0)? At this time, we will use monotone queue (Note: segment tree can also be used).
Monotone queue is equivalent to monotone stack, but it can also be deleted at the head of the queue (i.e\(head++\))。 Based on the above questions (i.e. examples)\(1\))For example, we only need to control the queue head of this monotonic queue to always meet the desired range. See examples for more detailed ideas\(1\)

Examples

P1886Sliding window / [template] monotonic queue

Carelessness

There is a long string\(n\)There is a long sequence\(m\)Windows from\(1\)reach\(n-m+1\)Sliding(\(0), find the maximum value of each sliding window.

thinking

Template questions.
Maintenance queue\(q\)Of course\(STL\)), (here we talk about the method of maximum value, and the same is true for minimum value) add one element at a time, and take the element smaller than this element out of the queue from the end of the queue (because the current element is larger than it and the window slides to the right, it must not become the maximum value again). Take the element not within the range from the head of the queue out of the queue from the head of the queue, and then the head of the queue is the maximum value.
In the code, first\(k-1\)Elements are queued and looped\(i\)\(k\le i\le n\)), enumerating queue tails, using\(push\)Function is inserted from the end of the queue and deleted from the head of the queue\(i-k+1\)The previous element, that is, the element that is no longer in the sliding window, outputs the team head.

code
#include
#include
#define maxn 1000005
using namespace std;
int n,k;
int a[maxn];
int q1[maxn],q2[maxn],h1=1,t1=0,h2=1,t2=0;// Q1 maintains the maximum value and Q2 maintains the minimum value 
int ans1[maxn],ans2[maxn];
void push1(int x,int l){
	while(t1>=h1&&a[x]>a[q1[t1]]){
		t1--;
	}
	q1[++t1]=x;
	while(t1>=h1&&q1[h1]=h2&&a[x]=h2&&q2[h2]
notes

Double experience (only maximum required):P2032scanning

P2629Good news, bad news

Carelessness

Given a ring, ask how many cases make the sum of accumulation time from any element\(tot\)Constant greater than or equal to\(0\)

thinking

Break loops into chains, maintain monotonic queues and prefixes\(pre_i\), if a length is\(n\)Sequence of\(i\sim i+n-1\)Minimum minus\(pre_{i-1}\)Greater than zero is feasible.

code
#include
#include
#define maxn 1000005
using namespace std;
int n,k;
int a[maxn*2],pre[maxn*2];
int q[maxn],h=1,t=0;
int ans[maxn];
void push(int x,int l){
	while(t>=h&&pre[x]=h&&q[h]=0){
			tot++;
		}
	}
	printf("%d",tot);
	return 0;
}

Monotone queue optimization DP

Examples

P1725cirno

Carelessness

There is a string of\(n+1\)Sequence of\(a\), from\(0\)Go, at a node\(i\)Can walk to\(i+l\sim i+r\)Anywhere,\(tot\)Accumulates the current position\(a_i\), find the maximum when leaving\(tot\)Value(\(i+r>n\)Representative from\(i\)Nodes can leave).

thinking

Obviously, the code complexity of this problem is\(O(N^2)\)\(f_i=\max\limits_{j=max(0,i-r)}^{i-l}{f_j}(l<=i<=n)\)Well, let’s just open a monotone queue to find the above\(max(f_j)\)Just.

code

(many details)

#include
#include
#include
#define maxn 1000005
#define INF 0x3f
using namespace std;
int n,l,r;
int a[maxn];
int q[maxn],h=1,t=0,maxx[maxn];
int f[maxn];
void push(int x,int l){
	while(f[x]>f[q[t]]&&h<=t){
		t--;
	}
	while(q[h]=l){
			push(i-l,max(0,i-r));
		}else{
			clear(max(0,i-r));
		}
		if(q[h]==-1){
			f[i]=f[maxn-1]+a[i];
		}else{
			f[i]=f[q[h]]+a[i];
		}
//		for(int j=i-l;j>=max(0,i-r);j--){
//			f[i]=max(f[i],f[j]+a[i]);
//		}
	}
	int ans=-INF;
	for(int i=n;i>=n-r+1;i--){
		ans=max(ans,f[i]);
	}
	printf("%d",ans);
	return 0;
}

P2627 Mowing the Lawn G

Carelessness

There is a length of\(n\)Select several elements so that the selected elements do not exceed continuously\(k\)Individual(\(0), find the maximum value of the sum of the selected elements.

thinking

The maximum value of the sum of the selected numbers can be converted into the minimum value of the sum of the deleted numbers.

code
#include
#include
#define maxn 100005
using namespace std;
long long n,k,a[maxn],f[maxn];
long long q[maxn],h=0,t=0;
long long tot=0;
void push(long long x,long long l){
	while(f[x]
notes

Double experience:P2034Select number

qzez1926Corn experiment

Carelessness

Given a\(n*n\)Matrix of\(a\)have\(t\)One inquiry, each inquiry in\((x_i,y_i)\)Upper left corner, length and width\(k\)What is the difference between the maximum value and the minimum value in the matrix of.

thinking

First, we can clearly get the code of violence:
\(ans_i = \max\limits_{x=x_i , y=y_i}^{x_i+k-1 , y_i+k-1}{a_{{x},{y}}} – \min\limits_{x=x_i , y=y_i}^{x_i+k-1 , y_i+k-1}{a_{{x},{y}}}\)
Then, because\(k\)Is given, which makes us think that monotone queue optimization can be used\(max(a_{{x},{y}})\)and\(min(a_{{x},{y}})\), i.e. preprocessing matrix\(a\), calculate the length of each row of the matrix\(k\)For the maximum value in the sliding window of the sub matrix, you can directly query the maximum value of the first column of the sub matrix.

code
#include
#include
#include
#define maxn 1005
#define INF 99999999
using namespace std;
int n,k,t,x,y;
int a1[maxn][maxn],a2[maxn][maxn];
int q1[maxn],q2[maxn],h1=1,t1=0,h2=1,t2=0;
int ans1[maxn][maxn],ans2[maxn][maxn];
Void push1 (int i, int x, Int l) {// find the minimum value 
	while(a1[i][x]a2[i][q2[t2]]&&h2<=t2){
		t2--;
	}
	q2[++t2]=x;
	while(q2[h2]

P4954 [USACO09OPEN]Tower of Hay G

Carelessness

Have a long\(n\)From left to right, divide it into several segments, so that the element sum of each segment is less than or equal to the element sum of the next segment, and calculate the maximum number of segments.

thinking

We first read the sequence in reverse order, so as long as the sum of each sequence element is greater than or equal to the sum of the following elements.\(sum_i\)Prefix and.

The first is violence.
We set\(f_i\)Before\(i\)The optimal case of two elements, and\(len_i\)Represents the element and minimum value of the last sequence in this optimal case. In this way, it is not difficult to deduce the expression:\(f_i=max(f_j)+1(0\le j < i , sum_i – sum_j\ge len_j)\)Even if\(j\sim i\)The sum of elements in the interval is greater than\(len_j\), that is, before\(j\)The minimum width of one can be\(i\)A period of punishment.
The code can get through the valleyVastdata

#include
#include
#define maxn 100005
using namespace std;
int n;
int a[maxn],sum[maxn],len[maxn],f[maxn];
int main(){
	scanf("%d",&n);
	for(int i=n;i>=1;i--){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=i-1;j>=0;j--){
			if(sum[i]-sum[j]>=len[j]){
				f[i]=f[j]+1;
				len[i]=sum[i]-sum[j];
				break;
			}
		}
	}
	printf("%d",f[n]);
	return 0;	
}

But we still need to improve,Otherwise, it does not conform to the title of monotonic queue optimization
be aware\(max(f_j)\)It seems that monotonic queue optimization can be used, so let’s study:
take\(sum_i – sum_j\ge len_j\)Shift to\(sum_i\ge len_j + sum_j\)At this time, we can maintain the monotone queue and store all the data that meet the above formula\(j\), and finally find it directly\(max(f_j)\)Just.

code
#include
#include
#define maxn 100005
using namespace std;
int n;
int a[maxn],sum[maxn],len[maxn],f[maxn];
int q[maxn],h=1,t=1;
int digit(int x){
	return sum[x]+len[x];
}
int main(){
	scanf("%d",&n);
	for(int i=n;i>=1;i--){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+a[i];
	}
	for(int i=1;i<=n;i++){
		int j=-1;
		while(h<=t&&sum[i]>=digit(q[h])){
			j=q[h++];
		}
		if(j!=-1){
			q[--h]=j;
		}
		f[i]=f[q[h]]+1;
		len[i]=sum[i]-sum[q[h]];
		while(h<=t&&digit(i)=0;j--){
//			if(sum[i]-sum[j]>=len[j]){
//				f[i]=f[j]+1;
//				len[i]=sum[i]-sum[j];
//				break;
//			}
//		}
	}
	printf("%d",f[n]);
	return 0;	
}

Recommended Today

Form regularity

Preface: onkeyup, onchange, oninput differences a、onkeyup = “value=value.replace(/[^\d]/g,”)” Using the onkeyup event, there is a bug, that is, in the state of Chinese input method, enter Chinese characters and enter letters directly b、onchange = “value=value.replace(/[^\d]/g,”)” Using onchange event, after inputting the content, the result will be obtained only when the input loses focus, and the […]