Luogu P2801 教主的魔法

在洛谷中查看


\(1\) 思路:

\(1.0\) 我们考虑使用分块做,但查询操作也不能预处理啊,\(c\) 可是 \(10^9\) 级别的。

\(\,\)

\(1.1\) 那么让我们来学习一下分块的找 大于/小于 \(c\) 的元素的个数的方法:

我们需要保证每次每个块内都是有序的,目的是为了查询时倍增或二分。
那么,一开始,我们先将每个块内排序(仅仅是每个块内,不是整体)。

然后看操作:

  1. 修改操作:将区间 \([ l , r ]\) 内的元素值都增加 \(w\)
    \(\quad\) 对于整块:打上懒标记,每块都还是有序的。
    \(\quad\) 对于散块:暴力修改,但要注意的是,我们已经排完序了,所以需要记录一下位置。修改完是可能无序的,所以要重新排序
    总时间复杂度:\(O(3\ Q\,\sqrt{n})\),即 \(O(9 \times 10^6)\)

\(\,\)

  1. 查询操作:查询区间 \([ 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;
}
posted @ 2023-08-19 01:52  今添  阅读(13)  评论(0)    收藏  举报