题目描述
现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。
语法:Q L
功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。
限制:L不超过当前数列的长度。
2、 插入操作。
语法:A n
功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。
限制:n是整数(可能为负数)并且在长整范围内。
注意:初始时数列是空的,没有一个数。
输入输出格式
输入格式: 第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)
接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。
对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。
输入输出样例
输入样例#1:5 100 A 96 Q 1 A 97 Q 1 Q 2输出样例#1:
96 93 96
说明
[JSOI2008]洛谷ac
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#define ll int
using namespace std;
const int maxn=800005;
const ll inf=(ll)2147483648;
ll _max[maxn],a[maxn],mod,ans=0,x;
int m,p=0,ql,qr;
inline ll get(){
char c;bool f=0;while(!isdigit(c=getchar()))if(c=='-')f=1;
ll v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
if(f)v=-v;return v;
}
inline void update(int node,int l,int r){
if(l==r)a[p]=_max[node]=x;
else{
int mid=(l+r)>>1;
if(p<=mid)update((node<<1),l,mid);
else update((node<<1)+1,mid+1,r);
_max[node]=max(_max[(node<<1)],_max[(node<<1)+1]);
}
}
inline ll query(int node,int l,int r){
ll mx=-inf;
if(ql<=l && qr>=r)mx=_max[node];
else{
int mid=(l+r)>>1;
if(ql<=mid)mx=max(query((node<<1),l,mid),mx);
if(qr>mid)mx=max(query((node<<1)+1,mid+1,r),mx);
}
return mx;
}
int main(){
m=(int)get();mod=get();
for(int i=1;i<=m;++i){
char c;
scanf("%c",&c);
if(c=='A'){
++p;
x=(int)get();
x=(x%mod+ans%mod)%mod;
update(1,1,m);
}
else{
int l=(int)get();
if(l<=0)continue;
ql=p-l+1;qr=p;
ans=query(1,1,m);
printf("%d\n",ans);
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#define ll long long
using namespace std;
const int maxn=800005;
const ll inf=(ll)2147483648;
ll _max[maxn],a[maxn],mod,ans=0,x;
int m,p=0,ql,qr;
inline ll get(){
char c;bool f=0;while(!isdigit(c=getchar()))if(c=='-')f=1;
ll v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
if(f)v=-v;return v;
}
inline void update(int node,int l,int r){
if(l==r)a[p]=_max[node]=x;
else{
int mid=(l+r)>>1;
if(p<=mid)update((node<<1),l,mid);
else update((node<<1)+1,mid+1,r);
_max[node]=max(_max[(node<<1)],_max[(node<<1)+1]);
}
}
inline ll query(int node,int l,int r){
ll mx=-inf;
if(ql<=l && qr>=r)mx=_max[node];
else{
int mid=(l+r)>>1;
if(ql<=mid)mx=max(query((node<<1),l,mid),mx);
if(qr>mid)mx=max(query((node<<1)+1,mid+1,r),mx);
}
return mx;
}
int main(){
m=(int)get();mod=get();
for(int i=1;i<=m;++i){
char c;
scanf("%c",&c);
if(c=='A'){
++p;
x=(int)get();
x=(x%mod+ans%mod)%mod;
update(1,1,m);
}
else{
int l=(int)get();
if(l<=0)continue;
ql=p-l+1;qr=p;
ans=query(1,1,m);
printf("%lld\n",ans);
}
}
return 0;
}
思路:裸的线段树点修改;
注意:队列的位置和结点的区别。