• 学数数——单调栈+前缀和维护


    学数数

     

     

     

    in

    3 5
    1 2 3
    > 1
    < 2
    = 3
    > 4
    < 5

    out

    5
    1
    3
    0
    6

     

     

    分析:

    其实我觉得我最大的问题就是把这题定死了是线段树,虽然说线段树也可以,因为这题只是利用它维护前缀和的功能,但更应该去思考的是如何整合这三种询问,并用一种好的方法解决问题。很显然的,对于三种询问可以只维护<的情况来表示三种情况,其中=为x-(x-1),意会一下;>只要知道题目说的总数为(n+1)*n/2就很好解决了。接着对于答案的求解,我们很显然可以发现一个数对答案的贡献与其左端和右端 第一个比它大(或等于)的数有关,当然为防止重复计数我们要规定一下左端是严格大于,右端是大于等于(可以自己列几个重复数字玩玩),这样贡献就是(左端数个数+本身)*(右端数个数+本身)。至于如何求左右两边比它大的数,可以用单调栈扫一遍。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define debug printf("zjyvegetable
    ")
    #define int long long
    #define mid ((l+r)>>1)
    #define lp (p<<1)
    #define rp (p<<1|1)
    inline int read(){
        int a=0,b=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')b=-1;c=getchar();}
        while(isdigit(c)){a=a*10+c-'0';c=getchar();}
        return a*b;
    }
    const int N=2e5+50,M=4e6+50;
    int n,q,m,total,top,a[N],b[N],sta[N],l[N],r[N],sum[N];
    int lowbit(int x){
        return x&-x;
    }
    void putin(int k,int z){
        for(;k<=m;k+=lowbit(k)){
            sum[k]+=z;
        }
    }
    int query(int k){
        int ans=0;
        for(;k;k-=lowbit(k))
        ans+=sum[k];
        return ans;
    }
    signed main(){
        freopen("jxthree.in","r",stdin);
        freopen("jxthree.out","w",stdout);
        n=read();q=read();
        total=(n+1)*n/2;
        for(int i=1;i<=n;i++)
        a[i]=b[i]=read();
        sort(b+1,b+n+1);
        m=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(b+1,b+m+1,a[i])-b;
        }
        for(int i=1;i<=n;i++){
            r[i]=i+1;
            if(!top){
                sta[++top]=i;
            }
            else{
                while(top&&a[sta[top]]<a[i]){
                    r[sta[top]]=i;
                    top--;
                }
                l[i]=sta[top];
                sta[++top]=i;
            }
        }
        while(top){
            r[sta[top]]=n+1;
            top--;
        }
        for(int i=1;i<=n;i++){
            putin(a[i],(i-l[i])*(r[i]-i));
        }
        char op[3];int u,v;
        for(int i=1;i<=q;i++){
            scanf("%s",op);v=read();
            u=lower_bound(b+1,b+m+1,v)-b;
            if(op[0]=='<')printf("%lld
    ",query(u-1));
            else if(op[0]=='='){
                if(b[u]!=v)printf("0
    ");
                else printf("%lld
    ",query(u)-query(u-1));
            }
            else{
                if(b[u]!=v)u--;
                printf("%lld
    ",total-query(u>m?m:u));
            }
        }
        return 0;
    }

    最后:

    其实对我来说,这题最大的收获是单调栈,主要是因为用的少,打上一遍后发现了很多细节和感受了单调栈的用处,算是收获满满吧。

  • 相关阅读:
    项目记录,仿今日头条app
    数组过滤后的重新排序问题
    用函数刷新页面内容比刷新页面要好
    html js绑定键盘按键触发事件(按回车键登陆)
    图片上传前压缩 lrz库
    微信 获取openid
    旅游项目总结
    UWP深入学习五: 传感器与搜索、共享及链接
    UWP深入学习四:动画及图像
    UWP深入学习三:依赖属性、附加属性和数据绑定
  • 原文地址:https://www.cnblogs.com/zjy1412/p/13399438.html
Copyright © 2020-2023  润新知