传送门
题目描述
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给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.区间每个元素均加上一个值
2.询问区间内>=k的个数
对于区间的操作,首先会想到线段树,但对于第二个操作,普通的线段树就有点无力了。对此,换个思路,考虑暴力的分块。
对于操作1:完整块直接标记(那么查询时c - add);部分块直接修改
对于操作2:完整块间考虑二分(对此,要另设数组,记录排序后的数组);部分块暴力查询
注意事项:
1.区间的分类处理
2.末区间本身就不完整
3.下面的程序中,a数组仅记录下标;同时,块部分修改后,整个块重新排序
4.为了方便,下标从0开始
代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define IL inline
#define open(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;
IL int read()
{
int sum = 0, k = 1;
char c = getchar();
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return sum * k;
}
int n, m;
int block;
int num[1000005], a[1000005];
struct Block
{
int val;
int l, r;
} blo[1005];
IL bool cmp(int x, int y)
{
return num[x] < num[y];
}
IL void update(int x, int y, int z)
{
for(int i = x; i <= y; ++i)
num[i] += z;
int k = x / block;
sort(a + blo[k].l, a + blo[k].r + 1, cmp);
}
IL int query1(int x, int y, int z)
{
int sum = 0;
for(int i = x; i <= y; ++i)
if(num[i] >= z) ++sum;
return sum;
}
IL int query2(int x, int y, int z)
{
int l = x, r = y, p = l - 1;
for(int mid; l <= r;)
{
mid = (l + r) >> 1;
if(num[a[mid]] < z)
{
p = mid;
l = mid + 1;
}else
{
r = mid - 1;
}
}
return y - p;
}
int main()
{
open("2801")
n = read(); m = read(); block = sqrt(n);
for(int i = 0, pre = 0, k = 0; i < n; ++i)
{
num[i] = read(); a[i] = i;
if(!((i + 1) % block) || i + 1 == n)
{
blo[k].r = i;
sort(a + blo[k].l, a + i + 1, cmp);
blo[++k].l = i + 1;
}
}
char c;
for(int i = 1, x, y, z, l, r, ans; i <= m; ++i)
{
scanf(" %c", &c);
x = read() - 1; y = read() - 1; z = read();
l = x / block; r = y / block;
if(c == 'M')
{
if(l == r) update(x, y, z); else
{
if(x != blo[l].l) {update(x, blo[l].r, z); ++l;}
if(y != blo[r].r) {update(blo[r].l, y, z); --r;}
for(; l <= r; ++l) blo[l].val += z;
}
}else
if(c == 'A')
{
if(l == r) ans = query1(x, y, z - blo[l].val); else
{
ans = 0;
if(x != blo[l].l) {query1(x, blo[l].r, z - blo[l].val); ++l;}
if(y != blo[r].r) {query1(blo[r].l, y, z - blo[r].val); --r;}
for(; l <= r; ++l) ans += query2(blo[l].l, blo[l].r, z - blo[l].val);
}
printf("%d\n", ans);
}
}
close
return 0;
}