Luogu P2801 教主的魔法
在洛谷中查看
\(1\) 思路:
\(1.0\) 我们考虑使用分块做,但查询操作也不能预处理啊,\(c\) 可是 \(10^9\) 级别的。
\(\,\)
\(1.1\) 那么让我们来学习一下分块的找 大于/小于 \(c\) 的元素的个数的方法:
我们需要保证每次每个块内都是有序的,目的是为了查询时倍增或二分。
那么,一开始,我们先将每个块内排序(仅仅是每个块内,不是整体)。
然后看操作:
- 修改操作:将区间 \([ l , r ]\) 内的元素值都增加 \(w\) 。
\(\quad\) 对于整块:打上懒标记,每块都还是有序的。
\(\quad\) 对于散块:暴力修改,但要注意的是,我们已经排完序了,所以需要记录一下位置。修改完是可能无序的,所以要重新排序。
总时间复杂度:\(O(3\ Q\,\sqrt{n})\),即 \(O(9 \times 10^6)\)。
\(\,\)
- 查询操作:查询区间 \([ l , r ]\) 内值大于等于 \(c\) 的元素的个数。
\(\quad\) 对于整块:因为我们维护了每块的顺序,所以每块都是有序的,我们可以对每块内倍增或二分。
\(\quad\) 对于散块:暴力查询。
总时间复杂度:\(O( Q \ \sqrt{n} \ \ log_\sqrt{n} \ )\),即 \(O(3 \times 10^7)\)。
其实这个时间复杂度有些不均匀,可以调整块长的。但是可以通过本题,因为数据太水了。
Code:(如果有不懂的,建议结合代码思考) (有些易错放到代码里了)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5, Sq = 1e3 + 15;//不知道需不需要开大点
int n, q;
int tot, siz, belong[N], L[Sq], R[Sq], cur[N];
ll tag[Sq];
struct Array {
ll v;
int id;
}a[N];
char opt;
inline int read() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { s = (s << 1) + (s << 3) + (c ^ 48); c = getchar(); }
return s * f;
}
bool cmp(Array a, Array b) {
return a.v < b.v;
}
void Sort(int l, int r) {
sort(a + l, a + r + 1, cmp);//将[l,r]排序,sort的参数是l,r+1
for (int i = l; i <= r; i++)cur[a[i].id] = i;//在原来的位置 ,不应该是 cur[i]=a[i].id !!!
}
void Make_block() {
tot = n / siz + (n % siz != 0);
for (int i = 1; i <= tot; i++) {
L[i] = (i - 1) * siz + 1;
R[i] = i * siz;
}
R[tot] = n;
for (int i = 1; i <= tot; i++)Sort(L[i], R[i]);//要将每个块内排序
}
int Binary_search(int block, int c) {
int l = L[block], r = R[block];
while (l < r) {
int mid = (l + r) >> 1;
if (a[mid].v + tag[block] >= c)r = mid;
else l = mid + 1;
}
if (a[l].v + tag[block] < c)return 0;//一个都不满足的时候
return R[block] - l + 1;
}
int main() {
n = read(), q = read(); siz = sqrt(n);
for (int i = 1; i <= n; i++)a[i] = (Array){ read(),i }, belong[i] = (i - 1) / siz + 1;
Make_block();
while (q--) {
cin >> opt;
int l = read(), r = read(), c = read();
int BL = belong[l], BR = belong[r];
if (opt == 'M') {//修改
if (BL == BR) {
for (int i = l; i <= r; i++)a[cur[i]].v += c;
Sort(L[BL], R[BL]);//这个块内可能不是有序的了
continue;
}
for (int i = l; i <= R[BL]; i++)a[cur[i]].v += c;
for (int i = L[BR]; i <= r; i++)a[cur[i]].v += c;
for (int i = BL + 1; i <= BR - 1; i++)tag[i] += c;
Sort(L[BL], R[BL]); Sort(L[BR], R[BR]);
//维护 a 数组,右边的散块必须维护!!!因为可能不是有序的了
}
if (opt == 'A') {//查询
ll sum = 0;
if (BL == BR) {
for (int i = l; i <= r; i++)sum += (a[cur[i]].v + tag[BL] >= c);
cout << sum << endl;
continue;
}
for (int i = l; i <= R[BL]; i++)sum += (a[cur[i]].v + tag[BL] >= c);
for (int i = L[BR]; i <= r; i++)sum += (a[cur[i]].v + tag[BR] >= c);
for (int i = BL + 1; i <= BR - 1; i++)sum += Binary_search(i, c);
cout << sum << endl;
}
}
return 0;
}

浙公网安备 33010602011771号