当前位置:网站首页>Monotonic stack

Monotonic stack

2022-07-06 06:37:00 cjwen6

Stack

The stack is OI A linear data structure commonly used in .

The stack is modified according to the principle of last in first out , So stack is usually called last in first out (last in first out) surface , abbreviation LIFO surface .

The following uses the name st , The bottom of the stack is st[1] , The top of the stack is st[top] Array simulation stack .

The advantage of this is , It is easy to operate :

operation Code
Size of query stack top
Check if the stack is empty top
Query the top elements of the stack st[top]
Insert elements \(x\)st[++top] = x;
Pop up top element top--;

Monotonic stack

What is monotonous stack

seeing the name of a thing one thinks of its function , Monotone stack is a stack structure that satisfies monotonicity . Compared with monotonic queues , It only goes in and out at one end .

Strictly ?

Strict inequality : It only contains marks \(>\) or \(<\) The inequality of is called strict inequality .

Non strict inequality : Contain marks \(\leq\) or \(\geq\) The inequality of is called non strict inequality .

therefore 「 Strictly greater than 」 Namely \(>\),「 Strictly less than 」 Namely \(<\).

Strictly monotonically increasing ( reduce ), It refers to everything except the first element , Each element is strictly greater than ( Less than ) The former element .

application

Consider such a question : Given a sequence of Numbers , For each number , Before finding this number, the first number that is strictly greater than it .

Suppose the number sequence is :\([81, 45, 11, 0, 14, 26]\), Insert the elements into the stack in turn .

Pictured 1-1, At this time, the front \(4\) Elements , The next element to be inserted is \(14\).

chart 1-1( Figure since OI-Wiki)

In order to find \(14\) The first element larger than it , Maintain monotony , Will compare \(14\) Small elements pop up , Then it pops up \(0\) and \(11\)

Pictured 1-2, At this point in the stack \(14\) The previous element of is \(45\), therefore \(14\) The first element larger than it was \(45\).

chart 1-2( Figure since OI-Wiki)

Suppose the next inserted element is \(x\).

If \(14 \leq x\), So then \(14\) Definitely not ( Elements \(x\) Of ) answer , So \(14\) It's still small \(0, 11\) It is even less likely to be the answer .

If \(14 > x\), that \(14\) That's the answer. , Don't think about \(0, 11\).

therefore ,\(0, 11\) Will no longer contribute to the following answers ( influence ), It can pop up .

The idea of dealing with problems with monotony is Eliminate impossible options in time , Keep the strategy highly effective and orderly , So as to provide more conditions and possible methods for us to make decisions .

Code implementation

#include<iostream>
#include<cstdio>

using namespace std;

int main(){
	
	int n = 6;
	int a[6] = {81, 45, 11, 0, 14, 26}, ans[6] = { };
	int st[6] = { }, top = 0;
	
	for(int i = 0; i < n; i++){
		while(top && st[top] <= a[i]){ //  Pay attention to  top  Determine whether the stack is empty , It can only be judged if it is not empty 
			printf("pop %d.\n", st[top]);
			top--;
		}
		
		if(top){
			ans[i] = st[top];
		}else{
			ans[i] = -1; //  There is nothing bigger than this number , It outputs  -1
		}
		
		printf("push %d.\n", a[i]);
		st[++top] = a[i];
		
		printf("stack: ");
		for(int j = 1; j <= top; j++){
			printf("%d ", st[j]);
		}
		puts("\n");
		
	}
	
	printf("ans: ");
	for(int i = 0; i < n; i++){
		printf("%d ", ans[i]);
	}
	
	return 0;
}

Running results :

push 81.
stack: 81 

push 45.
stack: 81 45 

push 11.
stack: 81 45 11 

push 0.
stack: 81 45 11 0 

pop 0.
pop 11.
push 14.
stack: 81 45 14 

pop 14.
push 26.
stack: 81 45 26 

ans: -1 81 45 11 45 45 

Complexity of time and space

The spatial complexity is obviously \(O(n)\).

Look at the core of the code :

// ……
for(int i = 0; i < n; i++){
	while(top && st[top] <= a[i]){
		printf("pop %d.\n", st[top]);
		top--;
	}
	// ……
}
// ……

Pay attention to the inner layer while loop , It is used to pop up elements with the top of the stack smaller than the element to be inserted .

Each element is only pushed once , It will only come out of the stack once , So the inner layer while In total, the loop will only execute \(n\) Time , The time complexity of the whole monotone stack code is \(O(n)\).

Monotone stack simple application

Monotone stack template problem

Lougu P5788 【 Templates 】 Monotonic stack

Topic summary

Given a length of \(N\) Sequence of numbers , For each number , After finding this number, the first element that is strictly larger than it The subscript .

analysis

It is found that the monotonous stack cannot be processed , Consider doing the opposite .

At this point, you need to maintain a Strictly monotonic decreasing The stack , That is, pop up all elements smaller than it at the top of the stack before inserting elements .

If the stack is empty before inserting , The answer is \(0\), Otherwise, it is the top element .

One thing to pay attention to in this question is , What is required is the element Subscript , So the stack should store subscripts , Not data .

The subscript used for the title is \(1 \sim n\), For convenience, the subscript of the program is also used \(1 \sim n\).

Reference code

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 3e6 + 10;

int n, a[N], ans[N];
int st[N], top;

int main(){
	
	scanf("%d", &n);
	
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
	}
	
	for(int i = n; i > 0; i--){
		while(top && a[st[top]] <= a[i]){
			top--;
		}
		if(top){
			ans[i] = st[top];
		}else{
			ans[i] = 0;
		}
		st[++top] = i;
	}
	
	for(int i = 1; i <= n; i++){
		printf("%d ", ans[i]);
	}
	
	return 0;
}

Bad Hair Day

POJ 3250 Bad Hair Day

Luogu P2866 [USACO06NOV]Bad Hair Day S

Topic summary

Yes \(N (N \leq 80,000)\) First milk steak in a line , Each cow has a height \(h_{i}\), Ask each cow to see the sum of the hair of how many cows ahead .

analysis

cow A Saw the cow B Hair of , It's equivalent to cows B The hair of the cow A I saw it .

It is difficult to ask how many cows' hair each cow can see behind , But you can ask how many cows in front of you can see the hair of each cow , The final and of these two solutions are the same .

So the problem is transformed into 「 How many cows in front can see the hair of each cow 」.

Using the monotone stack , Maintain a Strictly monotonic decreasing The stack .

Reference code

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 8e4 + 10;

int n, x;
int st[N], top;
long long ans;

int main(){
	
	scanf("%d", &n);
	
	for(int i = 0; i < n; i++){
		scanf("%d", &x);
		while(top && st[top] <= x){
			top--;
		}
		ans += top;
		st[++top] = x;
	}
	
	printf("%lld\n", ans);
	
	return 0;
}

Monotonic stack offline processing RMQ problem

「 Templates 」ST surface

It's actually RMQ The template questions .

Luogu P3865 【 Templates 】ST surface

Topic summary

Given \(n\) Sum of numbers \(m\) Group inquiry , Each group of questions has a range \(l, r\), Find the maximum value of this interval .

What is the RMQ

RMQ It's English Range Maximum(Minimum) Query Abbreviation , It means that the query range is the largest ( Minimum ) value .

Common algorithms :

Algorithm Whether online Preprocessing time complexity The time complexity of a single inquiry Total time complexity Spatial complexity
ST surface On-line \(O(n \log n)\)\(O(1)\)\(O(n \log n + n) \approx O(n \log n)\)\(O(n \log n)\)
Line segment tree On-line \(O(n)\)\(O(log n)\)\(O(n + m \log n) \approx O(m \log n)\)\(O(n)\)
………………………………
Monotonic stack offline \(O(m \log m)\)\(O(\log n)\)\(O(m \log m + m \log n) \approx O(m \log m)\)\(O(n)\)

among \(n\) Is the size of the array ,\(m\) Is the number of queries .

You can go to RMQ - OI Wiki see .

Online and offline

If an algorithm can answer every query instantly , The algorithm is called On-line Of , Otherwise it is called offline Of .

analysis

Read in all queries , Then sort by the right end of the query from small to large .

Process elements in turn , Maintain strictly monotonically decreasing stacks .

If it reaches the right end of a query , Then binary monotone stack , Find the first subscript at the bottom of the stack that is larger than this query \(l\) The elements of , Record answer .

See code Notes for details .

Reference code

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10, M = 2e6 + 10;

struct qt{
	int id, l, r;
}q[M]; //  Structure storage query 

int n, a[N], m;
int st[N], top;
int ans[M];

bool cmp(qt x, qt y){
	return x.r < y.r;
} //  Sort by right endpoint from small to large 

int main(){
	
	scanf("%d%d", &n, &m);
	
	for(int i = 1; i <= n; i++){
		scanf("%d", &a[i]);
	}
	
	for(int i = 0; i < m; i++){
		q[i].id = i;
		scanf("%d%d", &q[i].l, &q[i].r);
	}
	
	sort(q, q+m, cmp);
	
	int nw = 0; //  Currently processed queries 
	
	for(int i = 1; i <= n && nw < m; i++){ //  Process each element in turn , Insert into the stack , Maintain strictly monotonically decreasing stacks 
		
		while(top && a[st[top]] <= a[i]){
			top--;
		}
		st[++top] = i;
		
		while(i == q[nw].r){ //  If the current processing reaches the right endpoint of a query ( Because the right endpoint may repeat , So use  while  Instead of  if)
			
			int l = 1, r = top; //  The first subscript in the dichotomy stack is larger than that of this query  l  The elements of 
			while(l < r){
				int mid = (l + r) / 2;
				if(st[mid] >= q[nw].l){
					r = mid;
				}else{
					l = mid + 1;
				}
			}
			ans[q[nw].id] = a[st[l]]; //  Record answer 
			
			nw++; //  Deal with the next problem 
		}
	}
	
	for(int i = 0; i < m; i++){
		printf("%d\n", ans[i]);
	}
	
	return 0;
}

summary

  1. Maintain a stack , Make the stored data monotonous , Such a stack is called a monotone stack .

  2. Monotone stack is used to solve 「 The element in the sequence is left / The first one on the right is bigger than it / Small elements 」.

  3. Because each element can go in and out of the stack at most once , So the time complexity is \(O(n)\).

  4. Monotone stacks are often combined with other algorithms , Common examples are dichotomy .

practice

Largest Rectangle in a Histogram

POJ 2559 Largest Rectangle in a Histogram

AcWing 131. The largest rectangle in the histogram

Topic summary

Given \(n\) The height of a column , Find the area of the largest rectangle in the polygon .

analysis

Observation found that , The largest rectangle must be a column high .

Enumerate each column , Find the first column shorter than it on the left , And the first shorter column on the right , You can calculate the area of the largest rectangle with this column as the height , Finally, take the maximum of all the answers .

「 Find the first column shorter than it on the left , And the first shorter column on the right 」 It can be processed with monotonic stack .

Reference code

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 1e5 + 10;

int n;
int h[N], l[N], r[N];
int st[N], top;
long long ans;

int main(){
	
	while(scanf("%d", &n), n != 0){
		
		ans = 0;
		
		for(int i = 1; i <= n; i++){
			scanf("%d", &h[i]);
		}
		
//		 Deal with the first shorter column on the left  
		top = 0;
		for(int i = 1; i <= n; i++){
			while(top && h[st[top]] >= h[i]){
				top--;
			}
//			if(top){
//				l[i] = st[top];
//			}else{
//				l[i] = 0;
//			}
//			 If  top == 0,st[top] == st[0] == 0, So it can also be written like this :
			l[i] = st[top];
			st[++top] = i;
		}
		
//		 Deal with the first column shorter than it  
		top = 0;
		for(int i = n; i > 0; i--){
			while(top && h[st[top]] >= h[i]){
				top--;
			}
			if(top){
				r[i] = st[top];
			}else{
				r[i] = n+1;
			}
			st[++top] = i;
		}
		
		for(int i = 1; i <= n; i++){
			ans = max(ans, (long long)(r[i]-l[i]-1)*h[i]);
		} //  Calculate the maximum area of the rectangle with each column as the height  
		
		printf("%lld\n", ans);
		
	}
	
	return 0;
}

this paper PDF download

Monotonic stack _ Full version _ Chen Juwen .pdf

原网站

版权声明
本文为[cjwen6]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202132017440348.html