BZOJ 1012 [JSOI2008] 最大数 maxnumber 题解&代码

题目简洁明了= =我就不详细说了,线段树最大值裸题

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

思路就是假设这个线段树全部都是插入操作= =于是线段树最大只有m个元素,这样就把问题简化为
1、查询区间[tot-L,tot-1]的最大值(tot是当前元素总数+1)
2、将tot处的元素修改为(n+t)%d
初始化线段树时所有元素均为0
线段树求区间最大值问题= =代码量不算大,属于简单线段树

/************************************************************** Problem: 1012 User: Rainbow6174 Language: C++ Result: Accepted Time:1232 ms Memory:15336 kb ****************************************************************/

#include<iostream>
#include<stdio.h>
using namespace std;
char c[5];
int m,q,a,b,tot;
long long MOD,ans,x,n,val[200005],add[800020],maxn[800020];
void maintain(int o,int l,int r)
{
    if(l!=r)
        maxn[o]=max(maxn[o<<1],maxn[(o<<1)+1]);
    else maxn[o]=val[l];
}
void addnum(int o,int l,int r)
{
    if(l>=a && r<=b)
    {
        maxn[o]=val[a]=x;
        return;
    }
    if(r<a || l>b)return;
    int mid=(l+r)/2;
    addnum(o<<1,l,mid);
    addnum((o<<1)+1,mid+1,r);
    maintain(o,l,r);
    return;
}
void getmax(int o,int l,int r)
{
    if(l>=a && r<=b)
    {
        ans=max(ans,maxn[o]);
        return;
    }
    if(r<a || l>b)return;
    int mid=(l+r)/2;
    getmax(o<<1,l,mid);
    getmax((o<<1)+1,mid+1,r);
    maintain(o,l,r);
    return;
}
int main(void)
{
    scanf("%d%lld",&m,&MOD);
    tot=1;
    for(int i=1;i<=m;i++)
    {
        scanf("%s%lld",&c,&n);
        if(c[0]=='A')
        {
            x=(ans+n)%MOD;
            a=tot;b=tot;
            addnum(1,1,m);
            tot++;
        }
        else
        {
            ans=0;
            a=tot-n;
            b=tot-1;
            getmax(1,1,m);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

你可能感兴趣的:(C++,线段树,bzoj)