BZOJ1012 = Luogu 1198
Tag: 线段树入门题
试题描述
维护一个序列,支持以下操作:
- 查询某位x个数中的最大值
- 向序列末尾插入一个数
n ,且n 为本次插入命令指定的常数C 与上一次询问结果的和对一个确定常数D取模。
一共有
分析
考虑用线段树维护。开始时创建一个大序列,全部设为−2147483647。每插入一个数,就将大序列中空闲部分的第一个数改为被插入的数,然后递归更新上层。复杂度O(n⋅log2n)。
参考程序
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define oo 2147483647
#define mid ((l+r)/2)
using namespace std;
int a[800005],n=0,m,d,t=0;
void build(int p,int l,int r){
if(r<l)return;
a[p]=-oo;
if(r>l)build(p*2,l,mid),build(p*2+1,mid+1,r);
}
void modify(int p,int l,int r,int pos,int val){
if(r<l)return;
if(r==l)a[p]=val;
else{
if(pos<=mid)modify(p*2,l,mid,pos,val);
else modify(p*2+1,mid+1,r,pos,val);
a[p]=max(a[p*2],a[p*2+1]);
}
}
int query(int p,int l,int r,int ql,int qr){
if(r<l||l>qr||r<ql)return -oo;
if(l>=ql&&r<=qr)return a[p];
return max(query(p*2,l,mid,ql,qr),query(p*2+1,mid+1,r,ql,qr));
}
int main(){
scanf("%d%d",&m,&d);
build(1,1,m);
for(int i=0;i<m;i++){
char c[10];int tmp;
scanf("%s%d",&c,&tmp);
if(c[0]=='Q'){
int qr=query(1,1,m,n-tmp+1,n);
t=qr;
printf("%d\n",qr);
}
if(c[0]=='A')modify(1,1,m,++n,(tmp+t)%d);
}
return 0;
}
P.S.
- 传说线段树数组最好开到原数组的4倍大小。
- 在洛谷上评测时,如果使用手写的
Max 宏,会TLE7个点。而使用std::max就不会。