洛谷——P2801 教主的魔法(线段树or分块)

P2801 教主的魔法

 

(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。

(2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。

 

线段树大法好

 

维护区间$max$和区间$min$

修改,正常修改即可,push_up操作修改的也只是区间最大值和最小值

 

关键在于查找,若当前区间的最大值$<=$所要查询的值,返回0

若当前区间的最小值$>=$所要查询的值,返回$r-l+1$

 

想不到啊,维护区间最大值和最小值还能进行这样的骚操作啊,还是太蒟了。。。qwq

 

这题分块可做,可蒟蒻(博主)不会啊。。。

#include<bits/stdc++.h>

#define N 10000000
using namespace std;

struct Segment{
    int l,r,mw,mi,f;
}tr[N];

void push_up(int k){
    tr[k].mi=min(tr[k<<1].mi,tr[k<<1|1].mi);
    tr[k].mw=max(tr[k<<1].mw,tr[k<<1|1].mw);
}

void build(int k,int l,int r){
    tr[k].l=l,tr[k].r=r;
    if(l==r) {scanf("%d",&tr[k].mi),tr[k].mw=tr[k].mi;return;}
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push_up(k);
}

void push_down(int k){
    if(tr[k].f){
        int f=tr[k].f;
        tr[k<<1].mi+=f,tr[k<<1].mw+=f;
        tr[k<<1].f+=f,
        tr[k<<1|1].mi+=f,tr[k<<1|1].mw+=f;
        tr[k<<1|1].f+=f,
        tr[k].f=0;
    }
}

void update(int k,int ql,int qr,int f){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=ql&&r<=qr) {tr[k].mi+=f,tr[k].mw+=f;tr[k].f+=f;return;}
    push_down(k);
    if(ql<=mid) update(k<<1,ql,qr,f);
    if(qr>mid) update(k<<1|1,ql,qr,f);
    push_up(k);
}

int query(int k,int ql,int qr,int val){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=ql&&r<=qr&&tr[k].mi>=val) return r-l+1;
    if(l>=ql&&r<=qr&&tr[k].mw<val) return 0;
    push_down(k);
    int ans=0;
    if(ql<=mid) ans+=query(k<<1,ql,qr,val);
    if(qr>mid) ans+=query(k<<1|1,ql,qr,val);
    push_up(k);
    return ans;
}

int n,q;

int main()
{
    scanf("%d%d",&n,&q);
    build(1,1,n);
    for(int l,r,x,i=1;i<=q;i++){
        char p;
        cin>>p;
        scanf("%d%d%d",&l,&r,&x);
        if(p=='M') update(1,l,r,x);
        else{
            printf("%d\n",query(1,l,r,x));
        }
    }
    
    return 0;
}

 

posted @ 2018-10-10 22:30  清风我已逝  阅读(173)  评论(0编辑  收藏  举报