线段树的话很显然了,插入,询问,注意建的数的大小就好M的4倍就够了。
#include
#define INF 0x7fffffff
using namespace std;
struct data{int l,r,mx;}t[800005];
int M,D,last,cnt;
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;t[k].mx=-INF;
if(l==r)return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
int ask(int k,int x,int y){
int l=t[k].l,r=t[k].r;
if(l==x&&r==y)return t[k].mx;
int mid=(l+r)>>1;
if(y<=mid)return ask(k<<1,x,y);
else if(x>mid)return ask(k<<1|1,x,y);
else return max(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
}
void in(int k,int d,int v){
int l=t[k].l,r=t[k].r;
if(l==r){
t[k].mx=v;return ;
}
int mid=(l+r)>>1;
if(d<=mid)in(k<<1,d,v);
else in(k<<1|1,d,v);
t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
}
int main()
{
scanf("%d%d",&M,&D);
cnt=0;
last=0;
int tmp;
build(1,1,M);
while(M--){
char s[5];
scanf("%s",s);
if(s[0]=='A'){
scanf("%d",&tmp);
tmp=(last+tmp)%D;
in(1,++cnt,tmp);
}
else {
scanf("%d",&tmp);
printf("%d\n",last=ask(1,cnt-tmp+1,cnt));
}
}
return 0;
}
然后注意到因为是询问后L个数中的最大值,所以当一个数插入到末尾时比前面的都大,则前面的数显然不是答案,所以可以直接弹出(比这个数小的弹出,所以是个递减的单调栈),然后询问时二分查找L这一位置即可,栈内存的是位置。
#include
#define INF 0x7fffffff
using namespace std;
int M,D,L,R,last,x,cnt;
int q[200005];
int a[200005];
char s[5];
int main()
{
R=-1;
scanf("%d%d",&M,&D);
while(M--){
scanf("%s",s);
if(s[0]=='A'){
scanf("%d",&x);
x=(x+last)%D;
a[++cnt]=x;
while(L<=R&&a[q[R]]<=x)R--;
q[++R]=cnt;
}
else {
scanf("%d",&x);
int d=*lower_bound(q,q+R+1,cnt-x+1);
last=a[d];
printf("%d\n",last);
}
}
return 0;
}