zl程序教程

您现在的位置是:首页 >  其它

当前栏目

最大数

最大数
2023-09-27 14:28:29 时间

最 大 数 最大数

题目

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

  1. 查询操作。
    语法: Q Q Q L L L
    功能:查询当前数列中末尾 L L L个数中的最大的数,并输出这个数的值。
    限制: L L L不超过当前数列的长度。 ( L > 0 ) (L>0) (L>0)
  2. 插入操作。
    语法: A A A n n n
    功能:将 n n n加上 t t t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则 t = 0 t=0 t=0),并将所得结果对一个固定的常数 D D D取模,将所得答案插入到数列的末尾。
    限制: n n n是整数(可能为负数)并且在长整范围内。

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

输入

第一行两个整数, M M M D D D,其中 M M M表示操作的个数, D D D如上文中所述。
接下来的 M M M行,每行一个字符串,描述一个具体的操作。语法如上文所述。

输出

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

样例输入

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

样例输出

96
93
96

数据范围

M ≤ 200 , 000 M≤200,000 M200,000
0 &lt; D &lt; 2 , 000 , 000 , 000 0&lt;D&lt;2,000,000,000 0<D<2,000,000,000

思路

首先,这道题是线段树题。
每一次的插入就可以当做在原来的基础上继续建树(但每次只建一个点),然后查询就是区间最大值。
注意:要用 l o n g long long l o n g long long!!!
(本人就因为一直用 i n t int int而卡了很久很久)

代码

#include<cstdio>
#include<iostream>
using namespace std;
long long tree[800001],m,d,t,x,n;
char c;
long long answer(long long now,long long l,long long r,long long left,long long right)//查询操作
{
    if (l>=left&&r<=right) return tree[now];
    long long mid=(l+r)/2,temp=-2147483647; 
    if (left<=mid) temp=answer(now*2,l,mid,left,right);
    if (right>mid) temp=max(temp,answer(now*2+1,mid+1,r,left,right));
    return temp;
}
void add(long long l,long long r,long long sum)//插入操作
{
    if (l==r)
    {
        tree[sum]=(x+t)%d;
        return ;
    }
    long long mid=(l+r)/2;
    if (n<=mid) add(l,mid,sum*2);
    else add(mid+1,r,sum*2+1);
    tree[sum]=max(tree[sum*2],tree[sum*2+1])%d;
    return;
}
int main()
{
    cin>>m>>d;//读入
    for (long long i=1;i<=m;i++)
    {
        cin>>c;//读入
        cin>>x;//读入
        if (c=='A')//插入操作
        {
            n++;
            add(1,m,1);
        }
        else cout<<(t=answer(1,1,m,n-x+1,n))<<"\n";//查询操作
    }
    return 0;
}