RT
我用分块的方法维护。对于修改操作,使用边界暴力,中间 delta 的做法。每次修改后放到 b 数组里进行排序,之后查询的时候二分查找每一块,边界暴力查找。
感觉思路上没有什么问题。但是具体实现的细节上可能出现了问题。
#include<stdio.h>
#include<algorithm>
#include<math.h>
#define int ll
int n, q, a[100010], belong[100010], b[100010];
int s, c, st[100010], ed[100010], delta[100010];
void pretreat() {
s = sqrt(n);
for(int i = 1; i <= n; i += s) st[++c] = i, ed[c] = min(i + s - 1, n);
rep(i, 1, c) rep(j, st[i], ed[i]) belong[j] = i;
rep(i, 1, s) std::sort(b + st[i], b + ed[i] + 1);
}
void range_add(int l, int r, int w) {
ri x = belong[l], y = belong[r];
if(x == y) {
rep(i, l, r) a[i] += w;
rep(i, 1, n) b[i] = a[i];
rep(i, 1, s) std::sort(b + st[i], b + ed[i] + 1);
return;
}
rep(i, l, ed[x]) a[i] += w;
rep(i, st[y], r) a[i] += w;
rep(i, 1, n) b[i] = a[i];
rep(i, 1, s) std::sort(b + st[i], b + ed[i] + 1);
rep(i, x + 1, y - 1) delta[i] += w;
return;
}
int range_query(int bl, int w) {
int l = st[bl], r = ed[bl];
if(b[r] + delta[bl] < w) return 0;
while(l < r) {
int mid = l + r >> 1;
if(b[mid] + delta[bl] < w) l = mid + 1;
else r = mid;
}
while(b[r] + delta[bl] < w) ++r;
//printf("%d %d %d %d\n", ed[bl], bl, w, r);
return (ed[bl] - r + 1);
}
int query(int l, int r, int w) {
ri x = belong[l], y = belong[r];
//printf("%d %d\n", x, y);
if(x == y) {
int ans = 0;
rep(i, l, r) if(a[i] + delta[belong[i]] >= w) ++ans;
return ans;
}
int ans = 0;
rep(i, l, ed[x]) ans += ((a[i] + delta[belong[i]]) >= w);
rep(i, st[y], r) ans += ((a[i] + delta[belong[i]]) >= w);
rep(i, x + 1, y - 1) ans += range_query(i, w);
return ans;
}
signed main() {
read(n), read(q);
rep(i, 1, n) read(a[i]), b[i] = a[i];
pretreat();
while(q--) {
int l, r, w;
char op[1000];
scanf("%s ", op);
read(l), read(r), read(w);
if(op[0] == 'M') range_add(l, r, w);
else print(query(l, r, w), '\n');
}
return 0;
}
IO和预处理均已省略。