zoukankan      html  css  js  c++  java
  • 单调队列入门题

    单调队列:队列里的元素是单调的(只入队那些可能会影响答案的数据,一定不影响答案数据直接不入队)。复杂度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

  • 相关阅读:
    Spring Boot (20) 拦截器
    Spring Boot (19) servlet、filter、listener
    Spring Boot (18) @Async异步
    Spring Boot (17) 发送邮件
    Spring Boot (16) logback和access日志
    Spring Boot (15) pom.xml设置
    Spring Boot (14) 数据源配置原理
    Spring Boot (13) druid监控
    Spring boot (12) tomcat jdbc连接池
    Spring Boot (11) mybatis 关联映射
  • 原文地址:https://www.cnblogs.com/Yokel062/p/11346281.html
Copyright © 2011-2022 走看看