洛谷

https://www.luogu.org/problemnew/show/P1198

要问区间最大值,肯定是要用线段树的,不能用树状数组。(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊。不行!插入新元素之后更新的复杂度太高了!)

所以我们就弄一个初始元素是负数的最大值线段树,每次插入就是把末尾的元素 $update$ ,查询就是查询末尾的区间最大值,这样每次修改/查询的复杂度是 $O(nlogn)$ 的,非常给力。

所以说我又要到哪里抄一个线段树模板。

注意这个线段树是从1开始计数的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int MAXM=200000;
int a[MAXM+5],st[(MAXM<<2)+5];

void build(int o,int l,int r){
    if(l==r) st[o]=a[l];
    else{
        int m=l+((r-l)>>1);
        build(o<<1,l,m);
        build(o<<1|1,m+1,r);
        st[o]=max(st[o<<1],st[o<<1|1]);
    }
}

void update(int o,int l,int r,int id,int v){
    if(l==r) st[o]=v;
    else{
        int m=l+((r-l)>>1);
        if(id<=m) update(o<<1,l,m,id,v);
        else update(o<<1|1,m+1,r,id,v);
        st[o]=max(st[o<<1],st[o<<1|1]);
    }
}

int query(int o,int l,int r,int a,int b){
    if(r<a||l>b) return -1;
    if(a<=l&&r<=b) return st[o];
    int m=l+((r-l)>>1);
    int p1=query(o<<1,l,m,a,b),p2=query(o<<1|1,m+1,r,a,b);
    return max(p1,p2);
}


int M;
ll D;
int t;

char s[5];
int ins;

int cntA=0;

int main(){
    t=0;
    scanf("%d%lld",&M,&D);
    for(int i=1;i<=M;i++){
        a[i]=-1;
    }
    build(1,1,M);
    for(int i=1;i<=M;i++){
        scanf("%s%d",s,&ins);
        if(s[0]=='Q'){
            t=query(1,1,M,cntA-ins+1,cntA);
            printf("%d
",t);
        }
        else{
            update(1,1,M,cntA+1,((1ll*ins)+t)%D);
            cntA++;
        }
    }
}
原文地址:https://www.cnblogs.com/Yinku/p/10318840.html