Application of basic data structure one stack and queue
The application of monotone stack monotone queue and priority queue
First. Monotonic Stacks
The monotonic stack is a kind of data structure with strict monotonicity, which is divided into monotone increment stack and monotonically descending stack.
Monotonic Stacks have two properties
1. Meet the elements from the top of the stack to the bottom of the stack has strict monotonicity
2. Meet the last-in-first-out feature of the stack the sooner the element that is near the bottom of the stack
Elements into the stack process
For a monotonically incrementing stack, if the element of the current stack is a, a < stack top element will be directly a stack if a >= the top element of the current stack will continue to stack top elements out of the stack know to meet the A < stack top element
Simulate a sequence to construct a monotonically increasing stack
The input stack elements are 3,4,2,6,4,5,2,3 respectively.
First 3 the stack becomes {3};
Then 4 into the stack first let 3 out of the stack into the stack into {4};
2 The input stack becomes {4,2};
For 6 let 4, 2 out of the stack again let 6 into the stack {6};
4 into the stack {6,4};
Let 4 stack 5 into the stack {6,5};
Then 2 in 2 out of 3 into {6,5,3};
Because the monotonic stack can only operate on top of the stack, it is generally used only where there is a limit on one side of the array
Implementation of the implementation of the STL stack can be simulated stack is also OK
Second. Monotone queue
A monotone queue is a data structure in which an element within a queue has strict monotonicity, which is divided into monotone increment queue and monotonically descending queue.
Monotone queue satisfies two properties
1. The monotonic queue must meet the strict monotonicity from the head to the end of the team.
2. In front of the queue than the queue in order to the advanced team.
element into the queue process for a monotonically incrementing queue, for an element a if a > team tail element so directly throws a into the queue if a <= tail element will be the tail element out of the queue know that satisfies a is greater than the tail element;
The two-terminal queue can be implemented with STL.
Because the two-terminal queue can be in the team head operation can also be in the tail of the team so that the nature of the monotonous stack can only be in a single operation of the lack of the left also has a certain limit.
Question 1: give you n positive numbers. The weight of an interval is defined as the sum of all the numbers of the interval multiplied by the smallest number in the interval to find the maximum range of weights in all intervals.
Solve: It is not difficult for us to see what the longest interval is for each number as the minimum (or maximum), and we can consider using a monotone stack or a monotone queue for this kind of problem. Using a monotonically decreasing stack to maintain the maximum impact interval for each number is the previous number of stacks to the next to make this number out of the stack position. Each number in the stack can be seen as a wall. The minimum value of this wall becomes the number on the wall.
AC Code:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <stack>
using namespace std;
const int maxn = 1e5 + 10;
struct node{
long long num;
int pos;
};
node a[maxn];
long long sum[maxn] = {0};
int main(){
int n;
scanf("%d",&n);
int l = 1;
int r = n;
long long ans = 0;
for(int i = 1;i <= n; ++ i){
scanf("%lld",&a[i].num);
sum[i] = sum[i - 1] + a[i].num;
a[i].pos = i;
}
stack <node> st;
for(int i = 1;i <= n; ++ i){
if(st.empty()){
st.push(a[i]);
continue;
}
while(!st.empty() && st.top().num >= a[i].num){
node u = st.top();
st.pop();
int j;
if(!st.empty())
j = st.top().pos;
else{
j = 0;
}
long long temp = (sum[i - 1] - sum[j]) * u.num;
if(temp > ans){
ans = temp;
l = j + 1;
r = i - 1;
}
// cout << temp << endl;
}
st.push(a[i]);
}
int rr = n,ll = 1;
while(!st.empty()){
node u = st.top();
st.pop();
if(st.empty()){
ll = 0;
}
else{
ll = st.top().pos;
}
long long temp = (sum[rr] - sum[ll]) * u.num;
if(temp > ans){
ans = temp;
l = ll + 1;
r = rr;
}
// cout << temp << endl;
}
printf("%lld\n%d %d\n",ans,l,r);
return 0;
}
Question 2: Find the maximum area of the fence rectangle
The problem is very similar to the one above, and we just need a monotone stack to find the largest range of effects. Or with a descending monotone stack.
Question 3:poj 3017
Divides a sequence of n non-negative integers into segments, requiring each segment number and not exceeding m, to find the maximum and minimum partitioning method for each segment, and to output the smallest and
Solve: It is not difficult for us to think of a 1d/1d equation in which the state is a one-dimensional transfer to O (n) But the time complexity of O (n ^ 2) is unacceptable.
DP (i) represents the maximum and minimum of the first I divided into several segments.
Dp[i] = min (Dp[j] + maxnum{a[j + 1] ... A[i]});
For this equation, it is not difficult to find that DP (i) is monotonically incrementing and then it can be found that the maxnum is monotonically increasing from right to left and can be maintained with a monotone queue.
Suppose X is A[j + 1] ... A[i] The position of the maximum value, i.e. a[x] = maxnum{a[j + 1] ... A[i]}
• For any y to satisfy y >= J && y < x maxnum{a[y + 1] ... A[i]} is a constant value, a[i] is not negative, then dp[i] is monotonous
• In the case of dp[i], the maximum equal range should take the front
So we can use the monotone queue plus mutiset to optimize it to the NLOGN level to be able to AC
AC Code:
//#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
long long a[maxn] = {0};
long long sum[maxn] = {0};
int n,m;
long long dp[maxn] = {0};
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; ++ i){
scanf("%lld", &a[i]);
sum[i] = sum[i-1] + a[i];
}
for(int i = 1;i <= n; ++ i)
dp[i] = 10000000000000007;
dp[0] = 0;
dp[1] = a[1];
long long mm = a[1];
deque <int> dq;
dq.push_back(1);
for(int i = 2;i <= n; ++ i){
mm = max(mm,a[i]);
while(!dq.empty() && a[i] >= a[dq.back()]){
dq.pop_back();
}
dq.push_back(i);
while(!dq.empty() && sum[i] - sum[dq.front() - 1] > m)
dq.pop_front();
int l = lower_bound(sum + 1,sum + n + 1, sum[i] - m) - sum;
if(sum[i] - sum[l-1] > m)
l ++;
int k = dq.size();
for(int j = 0;j < k; ++ j){
dp[i] = min(dp[i],dp[l - 1] + a[dq.front()]);
int u = dq.front();
l = u + 1;
dq.pop_front();
dq.push_back(u);
}
}
if(mm > m)
printf("-1\n");
else
printf("%lld\n",dp[n]);
return 0;
}