[BZOJ1012] [JSOI2008] 最大数

来源:互联网 发布:麦当劳和肯德基 知乎 编辑:程序博客网 时间:2024/05/21 11:45

BZOJ1012 = Luogu 1198
Tag: 线段树入门题


试题描述
维护一个序列,支持以下操作:

  • 查询某位x个数中的最大值
  • 向序列末尾插入一个数n,且n 为本次插入命令指定的常数C与上一次询问结果的和对一个确定常数D取模。

一共有M个操作,满足M200000


分析
考虑用线段树维护。开始时创建一个大序列,全部设为2147483647。每插入一个数,就将大序列中空闲部分的第一个数改为被插入的数,然后递归更新上层。复杂度O(nlog2n)


参考程序

#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.

  1. 传说线段树数组最好开到原数组的4倍大小。
  2. 洛谷上评测时,如果使用手写的Max宏,会TLE7个点。而使用std::max就不会。
原创粉丝点击