现在请求你维护一个数列,要求提供以下两种操作: 1、 查询操作。 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。 限制:L不超过当前数列的长度。 2、 插入操作。 语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。 限制:n是非负整数并且在长整范围内。 注意:初始时数列是空的,没有一个数。
http://www.lydsy.com/JudgeOnline/problem.php?id=1012
/*
* 分析:
* 单调队列加暴力。
* 这个程序优化的地方:可以只存标号,每次Q操作的时候直接二分。
* */
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int X = 200005;
struct node{
int id,val;
}q[X];
int main(){
int n,m;
while(cin>>n>>m){
int pre = 0;
int x;
char op[2];
int head = 0,tail = 0;
int len = 0;
for(int i=1;i<=n;i++){
scanf("%s%d",op,&x);
if(op[0]=='A'){
x = (x+pre)%m;
while(tail&&q[tail-1].val<=x)
tail --;
q[tail].val = x;
q[tail++].id = ++len;
}
else{
for(int j=tail-1;j>=0;j--){
if(q[j].id+x<=len)
break;
else
pre = q[j].val;
}
printf("%d\n",pre);
}
}
}
return 0;
}
第二种方法:
/*
* 分析:
* 建立线段树
* 对于A操作,只需要update一下
* 对于Q操作,只需要query一下就好了。。
*
* */
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int X = 200002;
#define debug puts("here");
struct seg_tree{
int l,r;
int val;
int mid(){
return (l+r)>>1;
}
}tree[X<<2];
void build(int l,int r,int rt){
tree[rt].l = l;
tree[rt].r = r;
if(l==r)
return;
int mid = tree[rt].mid();
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void update(int pos,int val,int rt){
if(tree[rt].l==tree[rt].r){
tree[rt].val = val;
return;
}
int mid = tree[rt].mid();
if(mid>=pos)
update(pos,val,rt<<1);
else
update(pos,val,rt<<1|1);
tree[rt].val = max(tree[rt<<1].val,tree[rt<<1|1].val);
}
int query(int l,int r,int rt){
if(l<=tree[rt].l&&r>=tree[rt].r)
return tree[rt].val;
int mid = tree[rt].mid();
int ans = 0;
if(l<=mid)
ans = max(ans,query(l,r,rt<<1));
if(r>mid)
ans = max(ans,query(l,r,rt<<1|1));
return ans;
}
int main(){
int n,m;
while(cin>>n>>m){
char op[2];
int x;
int pre = 0;
int len = 0;
build(1,n,1);
while(n--){
scanf("%s%d",op,&x);
if(op[0]=='A')
update(++len,(pre+x)%m,1);
else{
pre = query(len-x+1,len,1);
printf("%d\n",pre);
}
}
}
return 0;
}