★★   输入文件:bzoj_1012.in   输出文件:bzoj_1012.out   简单对比
时间限制:3 s   内存限制:162 MB

【题目描述】

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

【输入格式】

第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足1≤int64max

【输出格式】

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

【样例输入】

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

【样例输出】

96
93
96

 

 

方法一 线段树 单点修改 RMQ 

方法二 维护一个单调栈 

BZOJ 1012: [JSOI2008]最大数maxnumber_水题集合BZOJ 1012: [JSOI2008]最大数maxnumber_水题集合_02
#include <cstdio>
#define Max 200000

typedef long long LL;
struct node
{
    LL Maxn,l,r,dis;
}tr[Max<<2];
LL M,D,pos=0,t=0;
LL max(LL a,LL b)
{
    return a>b?a:b;
}
void up(LL k)
{
    tr[k].Maxn=max(tr[k<<1].Maxn,tr[k<<1|1].Maxn);
}
void build(LL k,LL l,LL r)
{
    tr[k].l=l;
    tr[k].r=r;
    if(l==r)
    {
        tr[k].dis=0;tr[k].Maxn=0;
        return;
    }
    LL mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    up(k);
}
void add(LL k,LL t,LL v)
{
    if(tr[k].l==tr[k].r)
    {
        tr[k].dis+=v;
        tr[k].Maxn=tr[k].dis;
        return;
    }
    LL mid=(tr[k].l+tr[k].r)>>1;
    if(mid>=t) add(k<<1,t,v);
    else add(k<<1|1,t,v);
    up(k);
}
LL query(LL k,LL l,LL r)
{
    if(tr[k].l==l&&tr[k].r==r)
    return tr[k].Maxn;
    LL mid=(tr[k].l+tr[k].r)>>1;
    if(l>mid) return query(k<<1|1,l,r);
    else if(r<=mid) return query(k<<1,l,r);
    else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
}
int main()
{
    scanf("%lld%lld",&M,&D);
    build(1,1,M);
    char str[5];
    for(LL x;M--;)
    {
        scanf("%s",str+1);
        switch(str[1])
        {
            case 'A':
            {
                scanf("%lld",&x);
                add(1,++pos,(x+t)%D);
                break;
            }
            case 'Q':
            {
                scanf("%lld",&x);
                t=query(1,pos-x+1,pos);
                printf("%lld\n",t);
                break;
            }
        }
    }
    return 0;
}
线段树
BZOJ 1012: [JSOI2008]最大数maxnumber_水题集合BZOJ 1012: [JSOI2008]最大数maxnumber_水题集合_02
#include <bits/stdc++.h>
using namespace std;
#define N 200005
typedef long long LL;

void read(LL &x)
{
    x=0;bool f=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-') f=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    x=f?(~x)+1:x;
}
LL Num[N],s[N],top,cnt,a[N],M,D,t=0;
int main()
{
    read(M);
    read(D);
    char str[4];
    for(LL x;M--;)
    {
        scanf("%s",str+1);
        switch(str[1])
        {
            case 'A':
            {
                scanf("%lld",&x);
                LL y=(x+t)%D;
                a[++cnt]=y;
                while(top&&a[s[top]]<=y) top--;
                s[++top]=cnt;
                break;
            }
            case 'Q':
            {
                scanf("%lld",&x);
                int l=1,r=top;
                while(l<r)
                {
                    int mid=(l+r)>>1;
                    if(s[mid]<cnt-x+1) l=mid+1;
                    else r=mid;
                }
                int y=l;
                t=a[s[l]];
                printf("%lld\n",a[s[y]]);
                break;
            }
        }
    }
    return 0;
}
单调栈

 

我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。