zoukankan      html  css  js  c++  java
  • 单调队列、单调栈、优先队列模板

    单调栈、单调队列及优先队列

    1.单调队列

    单调队列的描述:指队列中元素之间关系具有单调性,而且队首和队尾都可以出队,但是只有队尾可以进行入队操作。其重要作用是找到前n个后者后n个数的最值。

    其具体操作是:假设单调队列是单调递减队列,假设在插入元素v时,将队列尾部的元素同v比较,如果队列尾部的元素不大于元素v,我们直接删除队尾元素,再将队尾元素与v比较,直至队尾元素比v大,这个时候我们将v插入队尾。其实现代码如下:

    int que[100];
    int head = 0, tail = 0;
    void push(int a)			//进队
    {
        que[++tail] = a;
    }
    int pop()			      //出队
    {
        return que[++head];
    }
    bool empty()		    	//判断队列是否为空
    {
        return !(head < tail);
    }
    

    下面是求一个整数序列中每k个中的最大值和最小值的代码:

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    const int maxn=1e6+10;
    int arr[maxn],que[maxn];
    
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
            scanf("%d",&arr[i]);
        int head=1,tail=0;
        for(int i=1;i<=n;++i){
            if(i==1){
                que[++tail]=i;
            }
            else{
                while(head<=tail&&arr[i]<arr[que[tail]])   tail--;
                que[++tail]=i;
                if(que[tail]-que[head]>=k)   head++;
            }
            if(i>=k)   printf("%d ",arr[que[head]]);
        }
        printf("
    ");
        head=1,tail=0;
        for(int i=1;i<=n;++i)
        {
            if(i==1)    que[++tail]=i;
            else{
                while(head<=tail&&arr[i]>arr[que[tail]]) tail--;
                que[++tail]=i;
                if(que[tail]-que[head]>=k)   head++;
            }
            if(i>=k)    printf("%d ",arr[que[head]]);
        }
        printf("
    ");
    }
    

    2.单调栈

    顾名思义,单调栈也是保持栈内元素单调递增或单调递减。在插入元素时仍需保持栈内元素的单调性。如现有单调栈,其栈内元素为:1 4 5,这时我们将元素3插入单调栈的话;我们需要先将4 5弹出栈在将3入栈,操作之后栈内元素变为1 3。单调栈似乎也可以通过单调队列实现...

    stack<int> S;
    for(int i=1 ;i<=n ;i++){
        while(S.size() && a[S.top()] >= a[i]) S.pop();
     
        if(S.empty())     L[i] = 0;
        else              L[i] = S.top();
     
        S.push(i);
    }
    

    代码:求最大矩形面积:

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn = 2010;
    typedef long long ll;
    int arr[maxn][maxn], top, st[maxn];
    int ans;
    int L[maxn], R[maxn];
    
    int main()
    {
        //ios::sync_with_stdio(false);
        int n,m;
        while (scanf("%d%d",&n,&m)!=EOF)
        {
            memset(R,0,sizeof(R));
            memset(L,0,sizeof(L));
            memset(st,0,sizeof(st));
            for (int i=1;i<=n;++i)
                for (int j=1;j<=m;++j)
                    scanf("%d",&arr[i][j]);
            for (int i =n-1;i>=1;--i)
                for (int j=1;j<=m;++j)
                    if(arr[i][j])
                        arr[i][j]+=arr[i+1][j];
            ans=-0x3f3f3f3f;
            for(int i=1;i<=n;++i)
            {
                top=0;
                for(int j=1;j<=m;++j)
                {
                    while(top>=1&&arr[i][j]<=arr[i][st[top]])
                        top--;
                    if(!top)
                        L[j]=1;
                    else
                        L[j]=st[top]+1; //在栈顶元素后一位
                    st[++top]=j;
                }
                top = 0;
                for(int j=m;j>= 1;--j)
                {
                    while(top>=1&&arr[i][j]<=arr[i][st[top]])
                        top--;
                    if (!top)
                        R[j]=m;
                    else
                        R[j]=st[top]-1; //在栈顶元素前一位,减一个1
                    st[++top]=j;
                }
                for(int j=1;j<=m;++j)
                    ans=max(ans,arr[i][j]*(R[j]-L[j]+1));
            }
            printf("%d
    ",ans);
        }
    }
    

    上面求的是最左边第一个比该数小和最右边第一个比该数小的用法,如果要求最右边或最右边第一个比该元素大,只需将while循环里面的<=改为>即可.

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn=1e5+10;
    typedef long long ll;
    ll arr[maxn],n;
    ll st[maxn],L[maxn],R[maxn],top;
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%d",&arr[i]);
        top=0;
        for(int i=1;i<=n;++i)
        {
            while(top>=1&&arr[i]>arr[st[top]])
                top--;
            if(!top)    L[i]=i;
            else        L[i]=st[top];
            st[++top]=i;
        }
        top=0;
        for(int i=n;i>=1;--i)
        {
            while(top>=1&&arr[i]>arr[st[top]])
                top--;
            if(!top)    R[i]=i;            //如果该元素作为次大值没有比它大的,那么最大值和次大值都是它本身
            else        R[i]=st[top];      //这里不需要加1或者减1,因为这就是比它大的第一个值的下标
            st[++top]=i;
        }
        ll res=-0x3f3f3f3f;
        for(int i=1;i<=n;++i){
            res=max(res,max(arr[i]^arr[L[i]],arr[i]^arr[R[i]]));
        }
        printf("%d
    ",res);
        system("pause");
    }
    

    3.优先队列

    优先队列是一个队列,优先级高的会先出队列,用法实例:

    priority_queue<int> a;
    priority_queue<node> b;
    priority_queue<int,vector<int>,greater<int> > c;		//注意最后两个>>不能写在一起,加个空格,否则是右移符号,与greater相似的还有less<int>...
    

    在默认情况下,优先队列会自动按降序(从大到小的顺序排列),less是从大到小,greater是从小到大,下面介绍优先队列的结构体用法和堆用法:

    1.优先队列装结构体

    有两种排序方式,在结构体外面和在结构体里面:

    struct node
    {
    	int x;
    	int y;
    	bool operator < (cosnt node& t){
    		return x>t.x;
    	}
    }
    bool operator < (const node& a,const node& b)
    {
    	return a.x>b.x;
    }										//在结构体外面的写法,上例会先输出x较小的
    

    下面是例题代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    int n,doct;
    struct node
    {
        int id;     //编号
        int q;      //优先级
        friend bool operator < (const node& a,const node& b)
        {
            if(a.q==b.q)    return a.id>b.id;
            return a.q<b.q;
        }           //优先级别排序
    }pat;
    priority_queue<node> arr[4];
    
    int main()
    {
        ios::sync_with_stdio(0);
        string str;
        int cnt=1;
        while(cin>>n&&n)
        {
            cnt=1;
            for(int i=1;i<=3;i++)
            {
                while(!arr[i].empty())
                    arr[i].pop();
            }                           //初始化
            while(n--)
            {
                cin>>str;
                if(str=="IN"){
                    cin>>doct>>pat.q;
                    pat.id=cnt++;
                    arr[doct].push(pat);
                }
                else{
                    cin>>doct;
                    if(arr[doct].empty())
                        cout<<"EMPTY"<<endl;
                    else{
                        cout<<arr[doct].top().id<<endl;
                        arr[doct].pop();
                    }
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    分布式理论基础(三)时间、时钟和事件顺序
    分布式理论基础(二)选举、多数派和租约
    分布式理论基础(一)一致性及解决一致性的两种方式:2PC和3PC
    spark入门(三)键值对操作
    spark入门(二)RDD基础操作
    Python的Flask框架入门-Ubuntu
    Python __str__(self)和__unicode__(self)
    Windows下安装和使用MongoDB
    Virtualenv介绍
    python的import与from…import的区别
  • 原文地址:https://www.cnblogs.com/StungYep/p/12254035.html
Copyright © 2011-2022 走看看