• 单调队列入门题


    单调队列:队列里的元素是单调的(只入队那些可能会影响答案的数据,一定不影响答案数据直接不入队)。复杂度O(2n)

    洛谷 P1440 链接

    题意:一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。

    题解:单调队列模板题,入队时弹出,出队时判断。这题用j解除流绑定的cin还是会超时...

    #include <bits/stdc++.h>
    using namespace std; 
    #define _for(i,a,b) for(int i=(a); i< (b); i++)
    #define _rep(i,a,b) for(int i=(a); i<=(b); i++)
    typedef long long ll; 
    
    const int MAXN=2e6+5; 
    
    struct Que{
        int idx, val;
    }q[MAXN];
    int a[MAXN];
    
    int main()
    {
        //ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
        int n, k;
        scanf("%d%d", &n, &k);
        _rep(i, 1, n) scanf("%d", &a[i]);
        int front=1, back=0;
        _rep(i, 1, n)
        {
            if(front>back) printf("0
    ");
            else
            {
                while(q[front].idx+k<i)
                    front++;
                printf("%d
    ", q[front].val);
            }
            while(back>=front && q[back].val>=a[i]) 
                back--;
            q[++back].val=a[i]; q[back].idx=i;
        }    
        return 0;
    }
    View Code

    HDU 3530

    题意:找一个最长的子序列,使其中的最大值-最小值的范围在[m, k]

    题解:这题错了好多次呀。开始的想法是:二分长度len,然后再用2个单调队列维护每一个长度为len的区间最大最小值,再判断是否满足。这是不对的,这个答案不满足单调性。长度为len时候不满足,可能为len+1的时候满足。

       正解:通过单调队列扫一遍数组(维护尽可能长的满足条件的子区间),维护最大最小值,在判断条件是否满足,(缩小最值的差上界,再判断是否满足下界),因为这里要求长度,这里队列记录的是坐标。注意当求子区间的起始点坐标别弄错了。

    #include <bits/stdc++.h>
    using namespace std;
    #define _for(i,a,b) for(int i=(a); i< (b); i++)
    #define _rep(i,a,b) for(int i=(a); i<=(b); i++)
    
    const int MAXN=1e6+5;
    int a[MAXN], q1[MAXN], q2[MAXN];
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
        int n, m, k;
        while(cin>>n>>m>>k)
        {
            _rep(i, 1, n) cin>>a[i];
            int l1=1, l2=1, r1=0, r2=0;
            int front=1, ans=0;
            _rep(i, 1, n)
            {
                while(r1>=l1 && a[q1[r1]]<a[i]) r1--;
                while(r2>=l2 && a[q2[r2]]>a[i]) r2--;
                q1[++r1]=i; q2[++r2]=i;
                while(r1>=l1 && r2>=l2 && a[q1[l1]]-a[q2[l2]]>k)
                {
                    if(q1[l1]<q2[l2]) front=q1[l1++]+1;
                    else front=q2[l2++]+1;
                    //printf("!front=%d
    ", front);
                }
                if(r1>=l1 && r2>=l2 && a[q1[l1]]-a[q2[l2]]>=m)
                    ans=max(ans, i-front+1);
                
                // 以下是自己一直写错的代码
                // front(满足条件的子序列开头的位置)不是这样子更新的
                /* 
                while(r1>=l1 && r2>=l2 && a[q1[l1]]-a[q2[l2]]>k)
                {
                    if(q1[l1]<q2[l2]) l1++;
                    else l2++;
                    front=min(q1[l1], q2[l2]);
                    //printf("!front=%d
    ", front);
                }
                if(r1>=l1 && r2>=l2 && a[q1[l1]]-a[q2[l2]]>=m)
                    ans=max(ans, i-front+1);
                */ 
            }
            cout<<ans<<endl;
             
        }    
        return 0;
    }
    View Code

    BZOJ 1012  [JSOI2008]最大数maxnumber

    题意:现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
    个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
    上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
    模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
    数。

    题解:每次加入一个值,可能会更改比他这个值小的区间,单调队列往前扫即可。

    单调队列:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN=2e5+5;
    int m, d, t;
    int q[MAXN];
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        scanf("%d%d", &m, &d);
        int l=1, r=0;
        while(m--)
        {
            char cmd[10]; 
            scanf("%s", cmd);
            if(cmd[0]=='A')
            {
                int n; scanf("%d", &n);
                n=(n+t)%d;
                int tr=r;
                while(tr>=l && q[tr]<n){
                    q[tr]=n; tr--;
                }
                q[++r]=n;
            }
            else if(cmd[0]=='Q')
            {
                int L; scanf("%d", &L);
                t=q[r-L+1];
                printf("%d
    ", t);
            }
        }
        return 0;    
    } 
    View Code

    单调栈:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN=2e5+5;
    int m, d, t;
    int stk[MAXN], top;
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        scanf("%d%d", &m, &d);
        while(m--)
        {
            char cmd[10]; int p; 
            scanf("%s%d", cmd, &p);
            if(cmd[0]=='A')
            {
                p=(p+t)%d;
                for(int i=top; i; i--)
                    if(stk[i]<p) stk[i]=p;
                    else break;
                stk[++top]=p;
            }
            else 
                printf("%d
    ", t=stk[top-p+1]);
        }
        return 0;    
    } 
    View Code

     线段树

    #include <bits/stdc++.h>
    using namespace std;
    #define ls l, m, rt<<1
    #define rs m+1, r, rt<<1|1
    
    const int MAXN=2e5+5;
    const int INF=0x3f3f3f3f;
    int m, d, t;
    int tree[MAXN<<2];
    
    void push_up(int rt)
    {
        tree[rt]=max(tree[rt<<1], tree[rt<<1|1]);    
    }
    
    int query(int L, int R, int l, int r, int rt)
    {
        if(L<=l && r<=R) return tree[rt];
        
        int m=l+r>>1, ret=-INF;
        if(L<=m) ret=max(ret, query(L, R, ls));
        if(R> m) ret=max(ret, query(L, R, rs));
        return ret;                                          
    }
    
    void update(int x, int v, int l, int r, int rt)
    {
        if(l==r){
            tree[rt]=v; return ;
        }
        int m=l+r>>1;
        if(x<=m) update(x, v, ls);
        else update(x, v, rs);
        push_up(rt); 
    }
    
    void print(int l, int r, int rt)
    {
        printf("l=%d, r=%d, tree=%d
    ", l, r, tree[rt]);
        if(l==r) return ;
        int m=l+r>>1;
        print(ls); print(rs);
    }
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        scanf("%d%d", &m, &d);
        memset(tree, -0x3f, sizeof(tree));
        int pos=0;
        for(int i=0; i<m; i++)
        {
            //print(1, m, 1);
            char cmd[10]; int p; 
            scanf("%s%d", cmd, &p);
            if(cmd[0]=='A')
            {
                p=(p+t)%d;
                update(++pos, p, 1, m, 1);
            }
            else printf("%d
    ", t=query(pos-p+1, pos, 1, m, 1));
        }
        return 0;    
    }  
    View Code

    POJ 3017

  • 相关阅读:
    由于信号量apache启动问题
    argument list too long
    Read-only file system处理
    fuser
    strace命令基本用法
    c++ 对vector和deque进行逆序排序问题
    C++ 遍历vector容器的三种方式
    C++ 中关于重复读取ifstream中的内容所需要注意的问题
    C++中的文件写入和读取(文本文件方式,二进制方式)
    Unity DoTween插件 在代码中改变Ease(运动方式)
  • 原文地址:https://www.cnblogs.com/Yokel062/p/11346281.html
Copyright © 2020-2023  润新知