0x10 Basic Data Structure

Keywords: PHP

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

  1. If \(q[l] < I - m\) leads the team
  2. At this point \(l\) is the most \(j\) updated answer
  3. 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;
}

Posted by gbow on Sat, 27 Jul 2019 09:47:52 -0700