洛谷2801——分块
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。
输入输出格式
输入格式:
第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。
输出格式:
对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于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、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
【数据范围】
对30%的数据,N≤1000,Q≤1000。
对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。
思想:
这道题直接暴力很简单,主要时间肯定超,其中有两个很耗时的过程:
- 增加;这个问题可以用一个add数组进行优化:如果出现对某一整块进行增加的时候,不进行这次操作,直接处理add的值。
- 查询;用二分搜索块内,(其实C++自己有lower_bound,但是,好像自己写的速度会更高一点,我也不知道什么原因,反正这道题都能用)。
上代码:
# include <iostream>
# include <algorithm>
# include <cstdio>
# include <cmath>
using namespace std;
const int maxn = 1e6 + 9;
int n, q, a[maxn], b[maxn], l[maxn], r[maxn], belong[maxn], add[maxn], block, num;
void reset(int x) {
for (int i = l[x]; i <= r[x]; i++) {
b[i] = a[i];
}
sort(b + l[x], b + r[x] + 1);
}
int fin(int x, int val) {
int ll = l[x], rr = r[x], mid;
while (ll <= rr) {
mid = (ll + rr) / 2;
if (b[mid] < val)
ll = mid + 1;
else
rr = mid - 1;
}
return r[x] - ll + 1;
}
void bulid(void) {
block = int (sqrt(n));
num = n / block;
if (n%block) {
num++;
}
for (int i = 1; i <= num; i++) {
l[i] = (i - 1) * block + 1;
r[i] = i * block;
}
r[num] = n;
for (int i = 0; i <= num; i++) {
sort(b + l[i], b + r[i] + 1);
}
for (int i = 1; i <= n; i++) {
belong[i] = (i-1) / block+1;
}
}
void update(int left,int right,int val) {
if (belong[left] == belong[right]) {
for (int i = left; i <= right; i++) {
a[i] += val;
}
reset(belong[left]);
return;
}
for (int i = left; i <= r[belong[left]]; i++) {
a[i] += val;
}
reset(belong[left]);
for (int i = belong[left] + 1; i < belong[right]; i++) {
add[i] += val;
}
for (int i = l[belong[right]]; i <= right; i++) {
a[i] += val;
}
reset(belong[right]);
}
int ask(int left, int right, int val) {
int sum = 0;
if (belong[left] == belong[right]) {
for (int i = left; i <= right; i++) {
if (a[i] + add[belong[i]] >= val) {
sum++;
}
}
return sum;
}
for (int i = left; i <= r[belong[left]]; i++) {
if (a[i] + add[belong[i]] >= val) {
sum++;
}
}
for (int i = belong[left] + 1; i < belong[right]; i++) {
sum +=fin(i, val-add[i]);
}
for (int i = l[belong[right]]; i <= right; i++) {
if (a[i] + add[belong[i]] >= val) {
sum++;
}
}
return sum;
}
int main() {
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i];
}
char str[5];
int left, right, val;
bulid();
for (int i = 0; i < q; i++) {
scanf("%s%d%d%d", str, &left, &right, &val);
if (str[0] == 'M') {
update(left, right, val);
}
else if (str[0]=='A'){
cout << ask(left, right, val) << endl;;
}
else{}
}
return 0;
}
目前已过。