BZOJ1012 [JSOI2008]最大数maxnumber

题目描述:

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。

2、 插入操作。语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),

并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。

注意:初始时数列是空的,没有一个数。

 

题解:

我们考虑序列最多会有m个数,并且看到区间查询,想到线段树。

对于操作2,我们直接在线段树上区间求和即可。

对于操作1,我们转换一下,即每次在线段树末尾单点修改即可。

附上代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int m,d,idx;
long long maxx[1000100],t;
void pushup(int k)
{
    maxx[k]=max(maxx[k<<1],maxx[k<<1|1]);
}
void update(int l,int r,int p,long long v,int k)
{
    if(l==r)
    {
        maxx[k]=v;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=p)
        update(l,mid,p,v,k<<1);
    else
        update(mid+1,r,p,v,k<<1|1);
    pushup(k);
}
long long query(int l,int r,int x,int y,int k)
{
    if(x<=l&&r<=y)
        return maxx[k];
    int mid=(l+r)>>1;
    long long ans=0;
    if(x<=mid)
        ans=max(ans,query(l,mid,x,y,k<<1));
    if(y>mid)
        ans=max(ans,query(mid+1,r,x,y,k<<1|1));
    return ans;
}
int main()
{
    scanf("%d%d",&m,&d);
    for(int i=1;i<=m;i++)
    {
        char s[2];
        scanf("%s",s);
        if(s[0]=='A')
        {
            ++idx;
            long long x;
            scanf("%lld",&x);
            update(1,m,idx,(x+t)%d,1);
        }
        else
        {
            int x;
            scanf("%d",&x);
            t=query(1,m,idx-x+1,idx,1);
            printf("%lld\n",t);
        }
    }
}

 

posted @ 2018-10-24 09:18  jiangminghong  阅读(104)  评论(0编辑  收藏  举报