线段树【p2801】教主的魔法

Description

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。

每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)

CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。

WD巨懒,于是他把这个回答的任务交给了你。

Input

第1行为两个整数N、Q。Q为问题数与教主的施法数总和。

第2行有N个正整数,第i个数代表第i个英雄的身高。

第3到第Q+2行每行有一个操作:

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

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

Output

对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。

线段树做的,不过貌似正解是分块.(不会分块啊 emm

差点被输入搞疯的一个题,输入竟然有好多个空格 qwq.难受得一逼.

结果发现是自己查询操作忘了判边界

维护区间最小值,维护\(tag\)标记.

暴力去找某个区间最小值\(\geq C\),直接累计答案.

不要忘记下放\(tag\)和判断\(l==r\)

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#define R register
#define ls o<<1
#define rs o<<1|1
#define N 1000008
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m,tg[N<<3],mnn[N<<3];
inline void up(int o)
{
    mnn[o]=min(mnn[ls],mnn[rs]);
    return;
}
inline void down(int o)
{
    if(tg[o])
    {
        tg[ls]+=tg[o];tg[rs]+=tg[o];
        mnn[ls]+=tg[o];mnn[rs]+=tg[o];
        tg[o]=0;
    }
    return;
}
void build(int o,int l,int r)
{
    if(l==r)
    {
        in(mnn[o]);
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(o);
}
void change(int o,int l,int r,int x,int y,int del)
{
    if(x<=l and y>=r)
    {
        tg[o]+=del;mnn[o]+=del;
        return;
    }
    down(o);
    int mid=(l+r)>>1;
    if(x<=mid) change(ls,l,mid,x,y,del);
    if(y>mid) change(rs,mid+1,r,x,y,del);
    up(o);
}
int query(int o,int l,int r,int x,int y,int k)
{
    if(mnn[o]>=k and x<=l and y>=r)
        return(r-l+1);;
    if(l==r)return 0;
    down(o);
    int mid=(l+r)>>1,res=0;
    if(x<=mid) res+=query(ls,l,mid,x,y,k);
    if(y>mid) res+=query(rs,mid+1,r,x,y,k);
    return res;
}
int main()
{
    in(n),in(m);
    build(1,1,n);
    for(R int l,r,z;m;m--)
    {
        R char opt[6];
        scanf("%s%d%d%d",opt,&l,&r,&z);
        if(opt[0]=='A')
            printf("%d\n",query(1,1,n,l,r,z));
        else change(1,1,n,l,r,z);
    }
}

转载于:https://www.cnblogs.com/-guz/p/9787920.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值