sort(区间排序)题解
题意简述:给定一个分好段且每一段长度都相同的数列,要求支持段内排序和查询前缀和。
朴素做法
按照题意模拟。排序操作时用 sort 进行排序,查询前缀和时直接从
cin >> n >> m >> len;
for (int i = 1; i <= n; i++) scanf("%d", a + i);
while (m--) {
int op, x;
cin >> op >> x;
if (op == 1)
sort(a + 1 + (x - 1) * len, a + 1 + x * len);
else {
int ans = 0;
for (int i = 1; i <= x; i++) ans += a[i];
printf("%d\n", ans);
}
}
特殊性质 1
考虑只存在操作
没有排序,那么
特殊性质 2
考虑
既然
无特殊性质
其实对于每一个
比如有一个长度为
现在假设有
- 对第一块进行排序。
- 对第二块进行排序。
- 对第三块进行排序。
- 查询前
8 个数的和。 - 查询前
5 个数的和。
首先可以发现,第
再考虑第二个询问,查询前
当然了,此做法会被卡:假如上面这个例子添加第 然而很玄学的事情发生了,不加这个优化,跑得反而比加上优化更快
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int n, m, len;
int a[N];
int f[N], s[N];
bool t[N];
int get(int x) {
if (x % len == 0) return x / len;
else return x / len + 1;
}
int main() {
cin >> n >> m >> len;
for (int i = 1; i <= n; i++) scanf("%d", a + i);
int cnt = 0;
for (int i = 1; i <= n / len; i++)
for (int j = 1; j <= len; j++) f[i] += a[++cnt];
for (int i = 1; i <= n / len; i++) s[i] = s[i - 1] + f[i];//预处理出前缀和
while (m--) {
int op, x;
cin >> op >> x;
if (op == 1) t[x] = true;//标记第 x 断需要排序。显然,如果 t[x] 等于 0,那么第 x 断就不需要排序了
else {
if (x % len == 0) {
cout << s[x / len] << endl;
continue;
}
int ans = s[x / len];//不需要排序的块的和
int k = get(x); //判断第 k 个数是第几段
if (t[k]) sort(a + 1 + (k - 1) * len, a + 1 + k * len), t[k] = false; //如果注释掉 t[k] = false,能跑得更快,离谱
for (int i = (k - 1) * len + 1; i <= x; i++) ans += a[i];//暴力求出新排序的块的和
printf("%d\n", ans);
}
}
return 0;
}