修改,就是一個區間修改的常規操做,可是爲了迎合查詢的須要,對兩端的不完整的塊須要暴力重構,從新進行排序操做,保證每一塊都是單調上升的順序。ios
而後再說進行查詢的操做,起初,咱們須要在每個塊內進行排序。保證順序時單調上升的(在每個塊內,是獨立的),而後查詢的時候對每一塊($k$)都二分查找到大於 $num + tag[k]$ 的第一個數的位置,而後就能夠獲得一共有多少大於 $num$ 的數了。ui
值得注意的是,有些題解寫的是對原序列直接進行排序,這就有一個錯誤,那就是在排序以後序列的順序改變,改變了以後在進行區間修改的時候就不能保證正確性了。spa
因此咱們開一個 vector 將每一個塊內的數都存下來。個人代碼 T 了一個點,可是了 O2 過了,懶得再去卡常了code
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <vector> using namespace std; const int maxn = 1e6+3; int N, Q, arr[maxn], in[maxn], cnt, tag[maxn]; vector<int> b[1003]; struct BLOCK { template <typename T> inline void read(T &x) { x = 0; T f = 1; char c = getchar(); while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();} x *= f; } void reset(int k) { b[k].clear(); for(int i=(k-1)*cnt+1; i<=min(k*cnt, N); i++) arr[i] += tag[k], b[k].push_back(arr[i]); sort(b[k].begin(), b[k].end()); tag[k] = 0; } void build() { cnt = sqrt(N); for(int i=1; i<=N; i++) { read(arr[i]); in[i] = (i-1)/cnt+1; b[in[i]].push_back(arr[i]); } for(int i=in[1]; i<=in[N]; i++) sort(b[i].begin(), b[i].end()); } void update(int l, int r, int num) { for(int i=l; i<=min(in[l]*cnt, r); i++) arr[i] += num; reset(in[l]); if(in[l] != in[r]) { for(int i=(in[r]-1)*cnt+1; i<=r; i++) arr[i] += num; reset(in[r]); } for(int i=in[l]+1; i<in[r]; i++) tag[i] += num; } int check(int k, int num) { int ans = (b[k].end()-lower_bound(b[k].begin(), b[k].end(), num-tag[k])); return ans; } int query(int l, int r, int num) { int ans = 0; for(int i=l; i<=min(in[l]*cnt, r); i++) if(arr[i] + tag[in[i]] >= num) ans ++; if(in[l] != in[r]) { for(int i=(in[r]-1)*cnt+1; i<=r; i++) if(arr[i] + tag[in[i]] >= num) ans ++; } for(int i=in[l]+1; i<in[r]; i++) ans += check(i, num); return ans; } BLOCK () { read(N), read(Q); build(); char opt; int l, r, num; for(int i=1; i<=Q; i++) { cin>>opt; read(l), read(r), read(num); if(opt == 'M') update(l, r, num); else printf("%d\n", query(l, r, num)); } } }BLO; int main() {}