0x11 stack
Stack is a LIFO linear data structure
AcWing 41.Stack containing min function
Maintain two stacks, one to record the value of the stack and the other to record the current minimum value.
cpp class MinStack { public: stack< int > a , b; MinStack() { } void push(int x) { a.push( x ); if( b.empty() || b.top() >= x ) b.push( x ); } void pop() { if( a.top() == b.top() ) b.pop(); a.pop(); } int top() { return a.top(); } int getMin() { return b.top(); } };
AcWing 128. Editor
Open two stacks of maintenance, similar to operations on the top stack, we call it the top stack
Make \(P\) the cursor position, two stacks separately \(a,b\)
Number before stack\(a\) store\(P\), number after stack\(b store\)P$
\(sum\) is the sum of prefixes, \(f\) is the maximum of the sum of prefixes
For operation \(L\), push \(x\) onto the stack \(a\) and update \(sum\) and \(f\)
For operation \(D\), stack \(a\) pop-up at the top of the stack
For operation \(L\), pop up the top of the stack \(a\) and press it onto the stack \(b\)
For operation \(R\), pop up the top of the stack \(b\) and press it onto the stack \(a\) to update \(sum) and \(f\)simultaneously
For operation \(Q\), return \(f[x]\)
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5 , INF = 0x7ffffff; int T , opt , a[N] , b[N] , sum[N] , f[N] , ta = 0 , tb = 0; inline int read( bool _ ) { register int x = 0 , f_ = 1; register char ch = getchar(); if( _ ) { while( ch < '0' || ch > '9' ) { if( ch == '-' ) f_ = -1; ch = getchar(); } while( ch >= '0' && ch <= '9') { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x * f_; } else { while( ch != 'L' && ch != 'R' && ch != 'I' && ch != 'D' && ch != 'Q' ) ch = getchar(); return int(ch); } } inline void work_1() { a[ ++ ta ] = read(1); sum[ta] = sum[ ta - 1 ] + a[ta]; f[ta] = max( sum[ta] , f[ ta - 1] ); return ; } inline void work_2() { if( ta > 0 ) ta --; return ; } inline void work_3() { if( ta > 0 )b[ ++ tb] = a[ ta ] , ta --; return ; } inline void work_4() { if( !tb ) return ; a[ ++ ta ] = b[tb]; tb --; sum[ta] = sum[ta - 1] + a[ta]; f[ta] = max( sum[ta] , f[ ta - 1] ); return ; } inline void work_5() { printf("%d\n",f[ read(1) ] ); return ; } int main() { f[0] = -INF; T = read(1); while( T -- ) { opt = read(0); if(opt == 'I' ) work_1(); else if(opt == 'D' ) work_2(); else if(opt == 'L' ) work_3(); else if(opt == 'R' ) work_4(); else work_5(); } return 0; }
AcWing 131. The largest rectangle in the histogram
Painters can discover patterns by playing with examples
Classic application of monotonic stack, but I'm lazy, STL+O2 goes straight over
#include <bits/stdc++.h> #pragma GCC optimize(2) #define LL long long using namespace std; const int N = 100005; int n , now , width ; LL res; struct node { int w , h; }_; stack< node > s; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x; } inline node make( int x , int y ) { _.h = x , _.w = y; return _; } int main() { while( 1 ) { n = read(); if( !n ) return 0; res = 0; for( register int i = 1; i <= n ; i ++ ) { now = read(); if( s.empty() || now > s.top().h ) s.push( make( now , 1 ) ); else { width = 0; while( !s.empty() && s.top().h > now ) { width += s.top().w; res = max( res , (LL)width * s.top().h ); s.pop(); } s.push( make( now , width + 1 ) ); } } width = 0; while( !s.empty() ) { width += s.top().w; res = max( res , (LL)width * s.top().h ); s.pop(); } printf( "%lld\n" , res ); } return 0; }
0x12 Queue
Queues are a "first in, first out" linear data structure that can be used to optimize space with circular queues when handwriting queues
Queues also have variants, preferred queues, monotonic queues, double-ended queues, all of which are present in \(STL\), but a larger constant than a regular queue can be handwritten
There are also priority queues in pbds
AcWing 132. Team
The question itself is not difficult, but the processing of the data is disgusting
Start with a queue for the maintenance team, and then \(n\) queues for each team member
Each time an element is pressed, it is added to the group's queue, and if the group's queue is empty, it is added to the total queue.
Each time an element pops up, a group of the head of the total queue is popped up, and if the queue of the head group is empty at this time, the head group is popped up from the total queue.
This question is not a very constant card. If you don't open \(O2\) it looks like it can pass.
In addition, it is not a good habit to jump into the queue, so be careful to be beaten
#include <bits/stdc++.h> #pragma GCC optimize(2) using namespace std; const int N = 1e6 + 5 , M = 1005; int n , t , m , num , cub[N]; string opt; map< int , queue<int> > member; queue< int > team; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) { x = ( x << 1 ) + ( x << 3 ) + ch - '0'; ch = getchar(); } return x; } inline void push() { num = read(); if( member[ cub[num] ].empty() ) team.push( cub[num] ); member[ cub[num] ].push( num ); return ; } inline void pop() { num = team.front(); printf( "%d\n" , member[ num ].front() ); member[ num ].pop(); if( member[ num ].empty() ) team.pop(); } inline void work( int k ) { n = read(); if( !n ) exit(0); printf( "Scenario #%d\n" , k ); while( !team.empty() ) { num = team.front(); while( !member[ num ].empty() ) member[ num ].pop(); team.pop(); } memset( cub , 0 , sizeof(cub) ); for( register int i = 1 ; i <= n ; i ++ ) { t = read(); while( t -- ) cub[ read() ] = i; } while( 1 ) { cin >> opt; if( opt == "ENQUEUE" ) push(); else if( opt == "DEQUEUE" ) pop(); else break; } puts(""); return ; } int main() { for( register int k = 1 ; 1 ; k ++ ) work(k); return 0; }
AcWing 135. Maximum Subordinates and
Base operations for monotonic queues
Firstly, the problem of interval sum is usually forward multiplied prefix and array, so make a difference.
Then there's the problem of finding the right and left endpoints
Make prefix and array \(s\)
Enumerated Right Endpoint\(i\) and Current Left Endpoint\(j\)
At this point any other \(k\) that satisfies \(k<j<i\) and \(s[k]>s[j]\), i s not likely to be the best solution at all, because for any \(i\) that can be selected \(j\) then \(j\) must be \(k\)better
So we find that we need to maintain a monotonically increasing sequence, and as \(i\) moves, some \(j\) will not work
Consistent with the nature of monotonic queues, they are maintained with monotonic queues, which store elements that are prefixes and subscripts to arrays, with a queue header of \(l\), and a queue tail of \(r\)
There are several operations for \(i\) of each enumeration
- If \(q[l] < I - m\) leads the team
- At this point \(l\) is the most \(j\) updated answer
- Maintain monotonic queue properties and put \(i\)in the queue
#include <bits/stdc++.h> using namespace std; const int N = 300000; int n , m , s[N] , q[N] , l = 1 , r = 1 , res ; inline int read() { register int x = 0 , f = 1; register char ch = getchar(); while( ch < '0' || ch > '9' ) { if( ch == '-' ) f = -1; ch = getchar(); } while( ch >= '0' && ch <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ch - '0'; ch = getchar(); } return x * f; } int main() { n = read() , m = read(); for( register int i = 1 ; i <= n ; i ++ ) s[i] = s[i-1] + read(); for( register int i = 1 ; i <= n ; i ++ ) { while( l <= r && q[l] < i - m ) l ++; res = max( res , s[i] - s[ q[l] ] ); while( l <= r && s[ q[r] ] >= s[i] ) r --; q[ ++ r ] = i; } cout << res << endl; return 0; }