[Luogu P2801] [BZOJ 3343] 教主的魔法

洛谷传送门
BZOJ传送门

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

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

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

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

输出格式:

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

输入输出样例

输入样例#1:

5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4

输出样例#1:

2
3

说明

【输入输出样例说明】

原先5个英雄身高为 1 1 2 3 3 4 5 5 ,此时[1,5]间有 2 2 个英雄的身高大于等于4。教主施法后变为 1 1 2 4 4 5 6 6 ,此时[1,5]间有 3 3 个英雄的身高大于等于4

【数据范围】

对30%的数据, N1000 N ≤ 1000 Q1000 Q ≤ 1000

对100%的数据, N1000000 N ≤ 1000000 Q3000 Q ≤ 3000 1W1000 1 ≤ W ≤ 1000 1C1,000,000,000 1 ≤ C ≤ 1 , 000 , 000 , 000

解题分析

分块裸题。

块内排序, 查询时二分。 修改整块打标记, 两端暴力。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 1000500
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    W (!isdigit(c)) c = gc;
    W (isdigit(c))
    x = (x << 1) + (x << 3) + c - 48, c = gc;
}
int dat[MX], bel[MX], siz[1005], tag[1005];
int dot, q, blk, bd;
IN void modify(R int lef, R int rig, R int del)
{
    R int l = bel[lef], r = bel[rig], bd;
    if(l == r)
    {
        for (R int i = lef; i <= rig; ++i) dat[i] += del;
        std::sort(dat + (l - 1) * blk + 1, dat + (l - 1) * blk + siz[l] + 1);
        return;
    }
    bd = (l - 1) * blk + siz[l];
    for (R int i = lef; i <= bd; ++i) dat[i] += del;
    std::sort(dat + (l - 1) * blk + 1, dat + bd + 1);
    bd = (r - 1) * blk + 1;
    for (R int i = bd; i <= rig; ++i) dat[i] += del;
    std::sort(dat + bd, dat + bd + siz[r]);
    for (R int i = l + 1; i < r; ++i) tag[i] += del;
}
IN int solve(R int lef, R int rig, R int tar)
{
    int l = lef, r = rig, mid, ans = 0;
    W (l <= r)
    {
        mid = l + r >> 1;
        if(dat[mid] >= tar) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    if(ans == 0) return 0;
    return rig - ans + 1;
}
IN int query(R int lef, R int rig, R int lim)
{
    R int ret = 0;
    R int l = bel[lef], r = bel[rig];
    if(l == r) return solve(lef, rig, lim - tag[l]);
    ret += solve(lef, (l - 1) * blk + siz[l], lim - tag[l]);
    ret += solve((r - 1) * blk + 1, rig, lim - tag[r]);
    for (R int i = l + 1; i < r; ++i)
    ret += solve((i - 1) * blk + 1, (i - 1) * blk + siz[i], lim - tag[i]);
    return ret;
}
int main(void)
{
    int a, b, c;
    in(dot), in(q);
    char buf[3];
    blk = std::sqrt(dot) + 1;
    for (R int i = 1; i <= dot; ++i) bel[i] = (i - 1) / blk + 1, siz[bel[i]]++;
    bd = bel[dot];
    for (R int i = 1; i <= dot; ++i) in(dat[i]);
    for (R int i = 1; i <= bd; ++i) std::sort(dat + blk * (i - 1) + 1, dat + blk * (i - 1) + siz[i] + 1);
    W (q--)
    {
        scanf("%s", buf), in(a), in(b), in(c);
        if(buf[0] == 'M') modify(a, b, c);
        else printf("%d\n", query(a, b, c));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值