洛谷传送门
BZOJ传送门
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是 N N 个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为、 2 2 、、 N N 。
每个人的身高一开始都是不超过的正整数。教主的魔法每次可以把闭区间 [L,R](1≤L≤R≤N) [ L , R ] ( 1 ≤ L ≤ R ≤ N ) 内的英雄的身高全部加上一个整数 W W 。(虽然时并不符合区间的书写规范,但我们可以认为是单独增加第 L L ()个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L,R] [ L , R ] 内有多少英雄身高大于等于 C C ,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。
输入输出格式
输入格式:
第行为两个整数 N N 、。 Q Q 为问题数与教主的施法数总和。
第行有 N N 个正整数,第个数代表第 i i 个英雄的身高。
第到第 Q+2 Q + 2 行每行有一个操作:
(1) 若第一个字母为“ M M ”,则紧接着有三个数字、 R R 、。表示对闭区间 [L,R] [ L , R ] 内所有英雄的身高加上 W W 。
(2) 若第一个字母为“”,则紧接着有三个数字 L L 、、 C C 。询问闭区间 内有多少英雄的身高大于等于 C C 。
输出格式:
对每个“”询问输出一行,仅含一个整数,表示闭区间 [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
说明
【输入输出样例说明】
原先个英雄身高为 1 1 、、 3 3 、、 5 5 ,此时间有 2 2 个英雄的身高大于等于。教主施法后变为 1 1 、、 4 4 、、 6 6 ,此时间有 3 3 个英雄的身高大于等于。
【数据范围】
对30%的数据, N≤1000 N ≤ 1000 , Q≤1000 Q ≤ 1000 。
对100%的数据, N≤1000000 N ≤ 1000000 , Q≤3000 Q ≤ 3000 , 1≤W≤1000 1 ≤ W ≤ 1000 , 1≤C≤1,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));
}
}