数列分块入门2
题目描述
给出一个长为 n n n 的数列,以及 n n n 个操作,操作涉及区间加法,询问区间内小于某个值 x x x 的元素个数。
输入格式
第一行输入一个数字
n
n
n。
第二行输入
n
n
n 个数字,第
i
i
i 个数字为
a
i
a_i
ai,以空格隔开。
接下来输入
n
n
n 行询问,每行输入四个数字
o
p
t
,
l
,
r
,
c
opt,l,r,c
opt,l,r,c,以空格隔开。
若
o
p
t
=
0
opt = 0
opt=0,表示将位于
[
l
,
r
]
[l, r]
[l,r] 的之间的数字都加
c
c
c。
若
o
p
t
=
1
opt = 1
opt=1,表示询问
[
l
,
r
]
[l, r]
[l,r] 中,小于
c
2
c^2
c2 的数字的个数。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入1:
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2
样例输出1:
3
0
2
数据范围
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 50000 1 \le n \le 50000 1≤n≤50000, − 2 31 ≤ o t h e r s , a n s ≤ 2 31 − 1 -2^{31} \le others,ans \le 2^{31} - 1 −231≤others,ans≤231−1。
题解
修改:散块修改时,有可能会打乱排序的顺序。因此需要修改后重新排序。整块还是用一个标记存区间加 a d d add add 的值。
查询:散块直接暴力判断。整块对块内元素进行排序,再用二分求出小于 c 2 − a d d c^2 - add c2−add 的数的个数。
#include<bits/stdc++.h>
using namespace std;
long long n, kuai_cnt, kuai_len;
long long a[50010], add[310], belong[50010];
vector<long long> v[310];
void reset(long long x){//重新排序
v[x].clear();
for(long long i = (x - 1) * kuai_len + 1; i <= min(x * kuai_len, n); ++ i){
v[x].push_back(a[i]);
}
sort(v[x].begin(), v[x].end());
}
void change(long long l, long long r, long long x){
for(long long i = l; i <= min(belong[l] * kuai_len, r); ++ i){
a[i] += x;
}
reset(belong[l]);
if(belong[l] != belong[r]){
for(long long i = (belong[r] - 1) * kuai_len + 1; i <= r; ++ i){
a[i] += x;
}
reset(belong[r]);
}
for(long long i = belong[l] + 1; i <= belong[r] - 1; ++ i){
add[i] += x;
}
}
long long query(long long l, long long r, long long x){
long long sum = 0;
for(long long i = l; i <= min(r, belong[l] * kuai_len); ++ i){
if(a[i] + add[belong[l]] < x){
++ sum;
}
}
if(belong[l] != belong[r]){
for(long long i = (belong[r] - 1) * kuai_len + 1; i <= r; ++ i){
if(a[i] + add[belong[r]] < x){
++ sum;
}
}
}
for(long long i = belong[l] + 1; i <= belong[r] - 1; ++ i){
long long t = x - add[i];
sum += lower_bound(v[i].begin(), v[i].end(), t) - v[i].begin();
}
return sum;
}
int main(){
scanf("%lld", &n);
for(long long i = 1; i <= n; ++ i){
scanf("%lld", &a[i]);
}
kuai_len = sqrt(n);
kuai_cnt = (n + kuai_len - 1) / kuai_len;
for(long long i = 1; i <= n; ++ i){
belong[i] = (i - 1) / kuai_len + 1;
v[belong[i]].push_back(a[i]);
}
for(long long i = 1; i <= kuai_cnt; ++ i){
sort(v[i].begin(), v[i].end());
}
for(long long i = 1; i <= n; ++ i){
long long op, l, r, d;
scanf("%lld %lld %lld %lld", &op, &l, &r, &d);
if(op == 0){
change(l, r, d);
}
else{
printf("%lld\n", query(l, r, d * d));
}
}
return 0;
}