题意:现在请求你维护一个数列,要求提供以下两种操作:
1、查询操作.
语法:Q L
功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
限制:\(L\)不超过当前数列的长度。\((L > 0)\)
2、 插入操作。
语法:A n
功能:将\(n\)加上\(t\),其中\(t\)是最近一次查询操作的答案(如果还未执行过查询操作,则\(t=0\)),并将所得结果对一个固定的常数\(D\)取模,将所得答案插入到数列的末尾。
限制:\(n\)是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数.
分析:本题好像还有什么树状数组,单调栈,ST表等多种做法,当做线段树模板题来写吧.对于查询操作就是区间\([n-L+1,n]\)最大值,线段树维护这个东西.对于一个插入操作,不妨把初始序列看做长度为200000的空线段树(每个值都是零),则插入操作就是单点修改操作了.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=200005;
int n,m,mod,last,a[N],maxn[N<<2];
inline void change(int p,int l,int r,int pos,int val){
if(r<pos||l>pos)return;
if(l==r&&l==pos){maxn[p]=val;return;}
int mid=(l+r)>>1;
change(p<<1,l,mid,pos,val);
change(p<<1|1,mid+1,r,pos,val);
maxn[p]=max(maxn[p<<1],maxn[p<<1|1]);
}
inline int ask(int p,int l,int r,int ql,int qr){
if(r<ql||l>qr)return -2e9;
if(ql<=l&&qr>=r)return maxn[p];
int mid=(l+r)>>1;
return max(ask(p<<1,l,mid,ql,qr),ask(p<<1|1,mid+1,r,ql,qr));
}
int main(){
m=read();mod=read();
while(m--){
char ch;cin>>ch;int x=read();
if(ch=='A'){
x=(x+last)%mod;a[++n]=x;
change(1,1,N-5,n,x);
}
else{
if(x==1){
last=a[n];
printf("%d\n",a[n]);
continue;
}
int l=n-x+1,r=n,ans=ask(1,1,N-5,l,r);
last=ans;printf("%d\n",ans);
}
}
return 0;
}