教主的魔法 线段树

教主的魔法

LG传送门

分块题,结果写了线段树。

查询的是区间内大于等于\(C\)的元素个数,维护一下区间最小值,修改照常,查询的时候改一下,如果碰到区间最小值都大于等于\(C\),就计算贡献,否则就继续往下分,这样就得到了整个区间内的个数。复杂度还是\(O(nlogn)\)

#include<cstdio>
#define R register
#define I inline
using namespace std;
const int S=1000003,M=4000003,inf=0x7fffffff;
int a[M],t[M],h[S],n,u;
I int min(int x,int y){return x<y?x:y;}
I void upd(int k,int v){a[k]+=v,t[k]+=v;}
I void psu(int k,int p,int q){a[k]=min(a[p],a[q]);}
I void psd(int k,int p,int q){upd(p,t[k]),upd(q,t[k]),t[k]=0;}
void bld(int k,int l,int r){
    if(l==r){a[k]=h[l]; return ;}
    R int m=l+r>>1,p=k<<1,q=p|1;
    bld(p,l,m),bld(q,m+1,r),psu(k,p,q);
}
void mdf(int k,int l,int r,int x,int y,int v){
    if(x<=l&&r<=y){upd(k,v); return ;}
    R int m=l+r>>1,p=k<<1,q=p|1;
    psd(k,p,q);
    if(x<=m) mdf(p,l,m,x,y,v);
    if(m<y) mdf(q,m+1,r,x,y,v);
    psu(k,p,q);
}
int qry(int k,int l,int r,int x,int y,int c){
    if(l==r&&a[k]<c) return a[k];
    if(x<=l&&r<=y&&a[k]>=c){u+=r-l+1; return a[k];}
    R int m=l+r>>1,p=k<<1,q=p|1,o=inf;
    psd(k,p,q);
    if(x<=m) o=min(o,qry(p,l,m,x,y,c));
    if(m<y) o=min(o,qry(q,m+1,r,x,y,c));
    return o;
}
int main(){
    R int q,i,x,y,z;
    R char p[2];
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;++i) scanf("%d",&h[i]);
    bld(1,1,n);
    for(i=1;i<=q;++i){
        scanf("%s%d%d%d",p,&x,&y,&z);
        if(p[0]=='M')
            mdf(1,1,n,x,y,z);
        else
            u=0,qry(1,1,n,x,y,z),printf("%d\n",u);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cj-chd/p/10118812.html
今日推荐