【bzoj3343】教主的魔法 分块+二分
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给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的英雄数。
样例输入
5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
样例输出
2
3
题解
分块+二分
分成√n 个块,对于每个块另开一个数组将h[i]排序。
修改时,整块直接打add标记,多余部分暴力改,然后重排序。
查询时,整块使用排序后的数组二分查找大于等于c-add的个数,多余部分暴力查询。
注意l和r同块时的特判。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n , si , h[1000010] , v[1000010] , add[1010];
char str[5];
void reset(int b)
{
int i , l = b * si , r = min((b + 1) * si - 1 , n - 1);
for(i = l ; i <= r ; i ++ ) v[i] = h[i];
sort(v + l , v + r + 1);
}
int search(int b , int lim)
{
int l = b * si , r = min((b + 1) * si - 1 , n - 1) , mid , ans = r + 1 , tr = r;
while(l <= r)
{
mid = (l + r) >> 1;
if(v[mid] + add[b] >= lim) ans = mid , r = mid - 1;
else l = mid + 1;
}
return tr - ans + 1;
}
int main()
{
int m , i , l , r , x , ans;
scanf("%d%d" , &n , &m);
si = (int)sqrt(n);
for(i = 0 ; i < n ; i ++ ) scanf("%d" , &h[i]);
for(i = 0 ; i * si < n ; i ++ ) reset(i);
while(m -- )
{
scanf("%s%d%d%d" , str , &l , &r , &x);
l -- , r -- ;
if(str[0] == 'M')
{
if(l / si == r / si)
{
for(i = l ; i <= r ; i ++ ) h[i] += x;
reset(l / si);
}
else
{
for(i = l / si + 1 ; i < r / si ; i ++ ) add[i] += x;
for(i = l ; i < (l / si + 1) * si ; i ++ ) h[i] += x;
for(i = r / si * si ; i <= r ; i ++ ) h[i] += x;
reset(l / si) , reset(r / si);
}
}
else
{
ans = 0;
if(l / si == r / si)
for(i = l ; i <= r ; i ++ )
ans += (h[i] + add[l / si] >= x);
else
{
for(i = l / si + 1 ; i < r / si ; i ++ ) ans += search(i , x);
for(i = l ; i < (l / si + 1) * si ; i ++ ) ans += (h[i] + add[l / si] >= x);
for(i = r / si * si ; i <= r ; i ++ ) ans += (h[i] + add[r / si] >= x);
}
printf("%d\n" , ans);
}
}
return 0;
}
浙公网安备 33010602011771号