「 Luogu P2801 」 教主的魔法——分塊

# 解題思路

修改,就是一個區間修改的常規操做,可是爲了迎合查詢的須要,對兩端的不完整的塊須要暴力重構,從新進行排序操做,保證每一塊都是單調上升的順序。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() {}
相關文章
相關標籤/搜索