题目链接https://loj.ac/problem/6278
内存限制:256 MiB时间限制:500 ms
题目描述
给出一个长为n 的数列,以及 n个操作,操作涉及区间加法,询问区间内小于某个值 x 的元素个数。
输入格式
第一行输入一个数字 。
第二行输入 n 个数字,第 i 个数字为 ai,以空格隔开。
接下来输入n 行询问,每行输入四个数字 opt,l,r,c以空格隔开。
若pot =0 ,表示将位于[l,r] 的之间的数字都加 。
若opt =1 ,表示询问 [l,r]中,小于c^2的数字的个数。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2
样例输出
3
0
2
数据范围与提示
对于 100% 的数据1<=n<=50000,-2^31<=others,ans<=2^31 -1.
这题和上一题差不多,只不过有个操作比较难以完成,就是查找区间小于x数的个数。
按照分块一贯的尿性,我们先将数列分为sqrt(n)块,然后计算一下它的块的端点,和每个点所属的块,我们这里用另外一个数组d复制一下a
int n;
cin >> n;
int t = sqrt(n);
for (int i = 1; i <= n; i++) cin >> a[i], d[i] = a[i];
for (int i = 1; i <= t; i++) {
L[i] = (i - 1) * t + 1;
R[i] = i * t;
}
if (R[t] < n)
t++, L[t] = R[t - 1] + 1, R[t] = n;
for (int i = 1; i <= t; i++)
for (int j = L[i]; j <= R[i]; j++) id[j] = i;
接下来我们要干什么呢?当然是将每个块有序化:
for (int i = 1; i <= t; i++)
sort(d + L[i], d + R[i] + 1);
这样操作之后每个块内的元素都是有序的,但又不影响原来的数组。
接下来就是常规操作了,对于update而言,我们在分块1的基础上多了一个操作:
int ll = id[l], rr = id[r];
for (int i = l; i <= R[ll]; i++) a[i] += w;
for (int i = L[ll]; i <= R[ll]; i++) d[i] = a[i];
sort(d + L[ll], d + R[ll] + 1);
也就是说l所属的块的元素的顺序被打乱了,我们需要重新排序。对于不属于l和r的块我们就不需要做任何操作,因为块中的每个元素加上同一个数的大小关系是不变的。
那么询问的时候也是老样子,对于l和r所属的块暴力查询,对l到r之间的块,由于它们是有序的,我们只需要找到第一个大于等于他的就好了,所以我们二分一下就出来了:
for (int i = ll + 1; i <= rr - 1; i++) {
int x = w - add[i];
ans += lower_bound(d + L[i], d + R[i] + 1, x) - (d + L[i]);
}
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
const int mac = 5e4 + 10;
int a[mac], add[300], id[mac], L[mac], R[mac];
int d[mac];
void update(int l, int r, int w) {
int ll = id[l], rr = id[r];
if (ll == rr) {
for (int i = l; i <= r; i++) a[i] += w;
for (int i = L[ll]; i <= R[ll]; i++) d[i] = a[i];
sort(d + L[ll], d + R[ll] + 1);
} else {
for (int i = l; i <= R[ll]; i++) a[i] += w;
for (int i = L[ll]; i <= R[ll]; i++) d[i] = a[i];
sort(d + L[ll], d + R[ll] + 1);
for (int i = ll + 1; i <= rr - 1; i++) add[i] += w;
for (int i = L[rr]; i <= r; i++) a[i] += w;
for (int i = L[rr]; i <= R[rr]; i++) d[i] = a[i];
sort(d + L[rr], d + R[rr] + 1);
}
}
int query(int l, int r, int w) {
int ll = id[l], rr = id[r];
int ans = 0;
if (ll == rr) {
for (int i = l; i <= r; i++)
if (a[i] + add[ll] < w)
ans++;
} else {
for (int i = l; i <= R[ll]; i++)
if (a[i] + add[ll] < w)
ans++;
for (int i = L[rr]; i <= r; i++)
if (a[i] + add[rr] < w)
ans++;
for (int i = ll + 1; i <= rr - 1; i++) {
int x = w - add[i];
ans += lower_bound(d + L[i], d + R[i] + 1, x) - (d + L[i]);
}
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
int t = sqrt(n);
for (int i = 1; i <= n; i++) cin >> a[i], d[i] = a[i];
for (int i = 1; i <= t; i++) {
L[i] = (i - 1) * t + 1;
R[i] = i * t;
}
if (R[t] < n)
t++, L[t] = R[t - 1] + 1, R[t] = n;
for (int i = 1; i <= t; i++)
for (int j = L[i]; j <= R[i]; j++) id[j] = i;
for (int i = 1; i <= t; i++) sort(d + L[i], d + R[i] + 1);
for (int i = 1; i <= n; i++) {
int opt, l, r, c;
cin >> opt >> l >> r >> c;
if (opt) {
int ans = query(l, r, c * c);
cout << ans << endl;
}
else update(l, r, c);
}
return 0;
}