• [bzoj 1012][JSOI2008]最大数maxnumber


    题面

    Description

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

    Input

      第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
    M行,查询操作或者插入操作。

    Output

      对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

    Sample Input

    5 100
    A 96
    Q 1
    A 97
    Q 1
    Q 2

    Sample Output

    96
    93
    96
     

    题解

    这里提供两种做法,单调队列和线段树

    先说一下线段树解法

    一.线段树解法

    首先看到这道题就能想到线段树吧

    这道题的线段树代码也很容易打,毕竟都没有lazy标记,就是单纯的点修改

    然后建树函数也可以不打的..这道题的插入其实就是一个建树的过程,如果不打建树函数的话代码前面memset一下-inf就好

    下面是代码:

    #include <cstdio>
    #include <cstring>
    #define ll long long
    #define inf 0x7fffffff
    #define il inline 
    il ll max(ll x,ll y){return x>y?x:y;}
    il ll min(ll x,ll y){return x<y?x:y;}
    il ll abs(ll x){return x>0?x:-x;}
    il void swap(ll &x,ll &y){ll t=x;x=y;y=t;}
    il void read(ll &x){
        x=0;ll f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    using namespace std;
    /*===================Header Template=====================*/
    #define N 200010
    ll t[N<<2],n,mod,len=0,T=0;
    void update(ll L,ll c,ll l,ll r,ll rt){
        if(l==r){t[rt]=c;return;}
        ll mid=(l+r)>>1;
        if(L<=mid)update(L,c,l,mid,rt<<1);
        else update(L,c,mid+1,r,rt<<1|1);
        t[rt]=max(t[rt<<1],t[rt<<1|1]);
    }
    ll query(ll L,ll R,ll l,ll r,ll rt){
        if(L<=l&&R>=r)return t[rt];
        ll mid=(l+r)>>1,ans=-inf;
        if(L<=mid)ans=max(ans,query(L,R,l,mid,rt<<1));
        if(R>mid)ans=max(ans,query(L,R,mid+1,r,rt<<1|1));
        return ans;
    }
    int main(){
        memset(t,128,sizeof(t));
        read(n);read(mod);
        for(ll i=1;i<=n;i++){
            char c=getchar();
            ll num;read(num);
            if(c=='A'){
                len++;
                update(len,(num+T)%mod,1,n,1);
            }else {
                if(num){
                    T=query(len-num+1,len,1,n,1)%mod;
                    printf("%lld
    ",T);
                }else {
                    printf("0
    ");
                    T=0;
                }
            }
        }
        return 0;
    }

      

    然而这道题是很玄学的,你把这个代码扔到洛谷上面会发现全部点MLE,然后在bzoj是能ac的...

    如果要在洛谷提交就看一下我的代码理解一下思路自己试着打一个,或者说看看下面的单调队列写法

    二.单调队列解法

     单调队列的写法就很简单了,但是很难想到这个做法,毕竟如果学过线段树第一时间想到的也会是线段树吧

    这里维护一下最大值就好

    #include <cstdio>
    #include <cstring>
    #define ll int
    #define inf 1<<30
    #define il inline 
    il ll max(ll x,ll y){return x>y?x:y;}
    il ll min(ll x,ll y){return x<y?x:y;}
    il ll abs(ll x){return x>0?x:-x;}
    il void swap(ll &x,ll &y){ll t=x;x=y;y=t;}
    il void read(ll &x){
        x=0;ll f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    using namespace std;
    /*===================Header Template=====================*/
    #define N 200010
    ll mx[N],a[N],p,m,mod,t,l=0;
    char c[1];
    int main(){
        read(m);read(mod);
        while(m--){
            scanf("%s%d",c,&p);
            if(c[0]=='A'){
                a[++t]=(l+p)%mod;
                for(ll i=t;i;i--){
                    if(mx[i]<a[t])mx[i]=a[t];
                    else break;
                }
            }else printf("%d
    ",l=mx[t-p+1]);
        }
        return 0;
    }

    转载请注明出处:https://www.cnblogs.com/henry-1202/p/9090699.html

  • 相关阅读:
    Vue部署到nginx刷新后出现404页面的问题
    移动端rem布局方案
    Vue使用Mint-ui的Popup, Picker组件报错问题
    Vue稍微高级一点的选项卡—动态组件
    GMOJ 1283排列统计 题解
    GMOJ 1281旅行 题解
    Why Did the Cow Cross the Road I P 题解
    【USACO 2017 December Gold】A Pie for a Pie 题解
    2020.05.23【NOIP提高组】模拟 总结
    2020.05.03【NOIP提高组】模拟 总结
  • 原文地址:https://www.cnblogs.com/henry-1202/p/9090699.html
Copyright © 2020-2023  润新知