BZOJ 1012 线段树或单调栈

线段树的话很显然了,插入,询问,注意建的数的大小就好M的4倍就够了。

#include 
#define INF 0x7fffffff
using namespace std;

struct data{int l,r,mx;}t[800005];
int M,D,last,cnt;
void build(int k,int l,int r){
    t[k].l=l;t[k].r=r;t[k].mx=-INF;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
int ask(int k,int x,int y){
    int l=t[k].l,r=t[k].r;
    if(l==x&&r==y)return t[k].mx;
    int mid=(l+r)>>1;
    if(y<=mid)return ask(k<<1,x,y);
    else if(x>mid)return ask(k<<1|1,x,y);
    else return max(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
}
void in(int k,int d,int v){
    int l=t[k].l,r=t[k].r;
    if(l==r){
        t[k].mx=v;return ;
    }
    int mid=(l+r)>>1;
    if(d<=mid)in(k<<1,d,v);
    else in(k<<1|1,d,v);
    t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
}
int main()
{
    scanf("%d%d",&M,&D);
    cnt=0;
    last=0;
    int tmp;
    build(1,1,M);
    while(M--){
        char s[5];
        scanf("%s",s);
        if(s[0]=='A'){
           scanf("%d",&tmp);
           tmp=(last+tmp)%D;
           in(1,++cnt,tmp);
        }
        else {
            scanf("%d",&tmp);
            printf("%d\n",last=ask(1,cnt-tmp+1,cnt));

        }
    }
    return 0;
}

然后注意到因为是询问后L个数中的最大值,所以当一个数插入到末尾时比前面的都大,则前面的数显然不是答案,所以可以直接弹出(比这个数小的弹出,所以是个递减的单调栈),然后询问时二分查找L这一位置即可,栈内存的是位置。

#include 
#define INF 0x7fffffff
using namespace std;

int M,D,L,R,last,x,cnt;
int q[200005];
int a[200005];
char s[5];

int main()
{
    R=-1;
    scanf("%d%d",&M,&D);
    while(M--){
        scanf("%s",s);
        if(s[0]=='A'){
          scanf("%d",&x);
          x=(x+last)%D;
          a[++cnt]=x;
          while(L<=R&&a[q[R]]<=x)R--;
          q[++R]=cnt;
        }
        else {
            scanf("%d",&x);
            int d=*lower_bound(q,q+R+1,cnt-x+1);
            last=a[d];
            printf("%d\n",last);
        }
    }
    return 0;
}

你可能感兴趣的:(BZOJ 1012 线段树或单调栈)