题目描述
现在请求你维护一个数列,要求提供以下两种操作:
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]
思路1:因为每次都只要末尾几个数中的最大值,考虑用单调栈维护。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int M,D,t=0;
int size;
int a[200500];
int num[200500];
int main()
{
int Ln,len=0;
char QA[5];
scanf("%d%d", &M, &D);
while(M--)
{
scanf("%s %d", QA, &Ln);
if(QA[0] == 'A')
{
Ln=(Ln+t)%D;
num[++len]=Ln;//每次加入一个Ln,num数组长度++
while(size&&num[a[size]]<=Ln)
size--;//单调栈操作
a[++size]=len;
}
else
{
int pos=lower_bound(a+1,a+size+1,len-Ln+1)-a; //二分查找
t=num[a[pos]];
cout<<t<<endl;
}
}
return 0;
}
思路2:线段树当然是可以解决的,只不过用蚊子来打大炮了。。。。
#include<iostream>
#include<cstdio>
using namespace std;
int n,p,t,len,a[200005*4],pos[200005*4];
void build(int x,int l,int r)
{
a[x]=-1000000000;
if(l==r){
pos[l]=x;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build((x<<1)+1,mid+1,r);
}
void change(int x,int len,int n)
{
a[pos[len]]=n;
int tmp=pos[len];
while(a[tmp]>a[tmp>>1]){
a[tmp>>1]=a[tmp];
tmp>>=1;
}
}
int query(int x,int l,int r,int sj,int tj)
{
if(l>tj||r<sj) return -10000000;
if(l>=sj&&r<=tj) return a[x];
int mid=(l+r)>>1;
return max(query(x<<1,l,mid,sj,tj),query((x<<1)+1,mid+1,r,sj,tj));
}
int main()
{
int i,x;
char flag;
scanf("%d%d",&n,&p);
build(1,1,n);
for(i=1;i<=n;i++){
cin>>flag;
cin>>x;
if(flag=='Q'){
printf("%d\n",t=query(1,1,n,len-x+1,len));
}
else change(1,++len,(x+t)%p);
}
}
此外,用树状数组也可以解决,不过yu处理比较麻烦,因为问的是最后几个数,而树状数组维护的是前几个数,所以需要反向读入。
设原数列为c,树状数组为a.
(实际编程时c是用不到的)
a中存最大值
先算出数列总长len。
建立树状数组的时候反向建立。
num存数列为空的长度,
即a[1]到a[num]为-maxlongint,a[num+1]到a[len]存有数据。
对于Q操作,即求c[1]到c[num+L]的最大值
对于A操作,在c[num]处更新。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=200005;
int n,p,t,len,a[MAXN*4],b[3][MAXN];
int Lowbit(int x)
{
return x&(-x);
}
void change(int n,int x)
{
while(n<=len){
a[n]=max(a[n],x);
n+=Lowbit(n);
}
}
int query(int x)
{
int ans=-100000000;
while(x>0){
ans=max(ans,a[x]);
x-=Lowbit(x);
}
return ans;
}
int main()
{
int i,num;
char flag;
scanf("%d%d",&n,&p);
for(i=1;i<=n;i++){
cin>>flag>>b[2][i];
if(flag=='A'){
b[1][i]=2;
b[2][i]%=p;
len++;
}
else{
b[1][i]=1;
}
}
num=len;
memset(a,128,sizeof(a));
for(i=1;i<=n;i++){
if(b[1][i]==1){
printf("%d\n",t=query(num+b[2][i]));
}
else{
change(num,(b[2][i]+t)%p);
num--;
}
}
return 0;
}