• [Loj] 数列分块入门 1


    数列分块入门 1

    https://loj.ac/problem/6277

    区间加 + 单点查询

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    const int N = 5e4 + 10;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    int A[N], Add[N], bel[N];
    int n, block, cnt;
    
    void Sec_G(int x, int y, int w) {
        if(bel[x] == bel[y]) for(int i = x; i <= y; i ++) A[i] += w;
        else {
            for(int i = x; i <= bel[x] * block; i ++) A[i] += w;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] += w; 
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] += w;
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1;
        if(n % block) cnt = n / block + 1;
        else cnt = n / block;
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(!opt) Sec_G(l, r, c);
            else cout << A[r] + Add[bel[r]] << endl;
        }
        return 0;
    }

    数列分块入门 2

    https://loj.ac/problem/6278

    区间加法,询问区间内小于某个值 x 的元素个数

    用B[]记录A[], B[]数组中为排好序的A[]的映射

    那么每次可以对每一块进行二分查找

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm> 
    
    using namespace std;
    const int N = 5e4 + 10;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    int A[N], B[N], Add[N], bel[N];
    int n, block, cnt;
    
    void Work_sort(int x) {
        int l = (x - 1) * block + 1, r = min(l + block - 1, n);
        for(int i = l; i <= r; i ++) B[i] = A[i];
        sort(B + l, B + r + 1);
    }
    
    void Sec_G(int x, int y, int w) {
        if(bel[x] == bel[y]) {
            for(int i = x; i <= y; i ++) A[i] += w;
            Work_sort(bel[x]);
        }
        else {
            for(int i = x; i <= bel[x] * block; i ++) A[i] += w; Work_sort(bel[x]);
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] += w; Work_sort(bel[y]);
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] += w;
    }
    
    inline int Calc(int x, int w) {
        int l = (x - 1) * block + 1, r = min(l + block - 1, n), ret = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(B[mid] + Add[x] < w) ret = mid, l = mid + 1;
            else r = mid - 1;
        }
        return ret ? (ret - (x - 1) * block) : 0;
    }
    
    inline int Sec_A(int x, int y, int w) {
        int ret(0);
        if(bel[x] == bel[y]) {
            for(int i = x; i <= y; i ++) if(A[i] + Add[bel[x]] < w) ret ++;
            return ret;
        } else {
            for(int i = x; i <= bel[x] * block; i ++) if(A[i] + Add[bel[x]] < w) ret ++;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) 
            if(A[i] + Add[bel[y]] < w) 
            ret ++;
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) 
        ret += Calc(i, w);
        return ret;
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1;
        if(n % block) cnt = n / block + 1;
        else cnt = n / block;
        for(int i = 1; i <= cnt; i ++) Work_sort(i);
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(!opt) Sec_G(l, r, c);
            else cout << Sec_A(l, r, c * c) << "
    ";
        }
        return 0;
    }

    数列分块入门 3

    https://loj.ac/problem/6279

    区间加法,询问区间内小于某个值 x 的前驱

    与2类似,二分查找

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm> 
    
    using namespace std;
    const int N = 1e5 + 10;
    const int oo = 999999999;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    int A[N], B[N] = {-1}, Add[N], bel[N];
    int n, block, cnt;
    
    void Work_sort(int x) {
        int l = (x - 1) * block + 1, r = min(l + block - 1, n);
        for(int i = l; i <= r; i ++) B[i] = A[i];
        sort(B + l, B + r + 1);
    }
    
    void Sec_G(int x, int y, int w) {
        if(bel[x] == bel[y]) {
            for(int i = x; i <= y; i ++) A[i] += w;
            Work_sort(bel[x]);
        }
        else {
            for(int i = x; i <= bel[x] * block; i ++) A[i] += w; Work_sort(bel[x]);
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] += w; Work_sort(bel[y]);
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] += w;
    }
    
    inline int Calc(int x, int w) {
        int l = (x - 1) * block + 1, r = min(l + block - 1, n), ret = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(B[mid] + Add[x] < w) ret = mid, l = mid + 1;
            else r = mid - 1;
        }
        return B[ret] + Add[x];
    }
    
    inline int Sec_A(int x, int y, int w) {
        int ret = -1;
        if(bel[x] == bel[y]) {
            for(int i = x; i <= y; i ++) if(A[i] + Add[bel[x]] < w && A[i] + Add[bel[x]] > ret) ret = A[i] + Add[bel[x]];
            return ret;
        } else {
            for(int i = x; i <= bel[x] * block; i ++) 
            if(A[i] + Add[bel[x]] < w && A[i] + Add[bel[x]] > ret) ret = A[i] + Add[bel[x]];
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) 
            if(A[i] + Add[bel[y]] < w && A[i] + Add[bel[y]] > ret) ret = A[i] + Add[bel[y]]; 
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) {
            int imp = Calc(i, w);
            if(imp < w && imp > ret) ret = imp;
        }
        return ret;
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1;
        if(n % block) cnt = n / block + 1;
        else cnt = n / block;
        for(int i = 1; i <= cnt; i ++) Work_sort(i);
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(!opt) Sec_G(l, r, c);
            else cout << Sec_A(l, r, c) << "
    ";
        }
        return 0;
    }

    数列分块入门 4

    区间加法,区间求和

    https://loj.ac/problem/6280

    没什么好说的

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    const int N = 5e4 + 10;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    #define LL long long
    
    LL A[N], Add[N], bel[N], W[N];
    int n, block, cnt, Mod;
    
    void Sec_G(int x, int y, int w) {
        if(bel[x] == bel[y]) for(int i = x; i <= y; i ++) A[i] += w, W[bel[x]] += w;
        else {
            for(int i = x; i <= bel[x] * block; i ++) A[i] += w, W[bel[x]] += w;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] += w, W[bel[y]] += w;
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] += w, W[i] += w * block;
    }
    
    inline int Sec_A(int x, int y) {
        LL ret = 0;
        if(bel[x] == bel[y]) 
            for(int i = x; i <= y; i ++)
                ret += (A[i] + Add[bel[x]]) % Mod;
        else {
            for(int i = x; i <= bel[x] * block; i ++) ret += (A[i] + Add[bel[x]]) % Mod;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) ret += (A[i] + Add[bel[y]]) % Mod;
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) ret += W[i] % Mod;
        return ret% Mod;
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1, W[bel[i]] += A[i];
        if(n % block) cnt = n / block + 1;
        else cnt = n / block;
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read(); Mod = c + 1;
            if(!opt) Sec_G(l, r, c);
            else cout << Sec_A(l, r) << endl;
        }
        return 0;
    }

    数列分块入门 5

    区间开方,区间求和

    一个数(合理)开几次根后就是0/1了

    因此,只需记录每块的最大值,如果最大值是0/1就没必要开根

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    const int N = 5e4 + 10;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    #define LL long long
    
    LL A[N], Add[N], bel[N], W[N], Max[N];
    int n, block, cnt, Mod;
    
    inline void Sec_G(int x, int y) {
        if(bel[x] == bel[y]) {
            if(!Max[bel[x]]) return ;
            if(Max[bel[x]] == 1) return ;
            for(int i = x; i <= y; i ++) {
                int C = A[i] - (int) sqrt(A[i]);
                W[bel[x]] -= C; A[i] = (int) sqrt(A[i]);
            }
            LL Max_A = 0;
            for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) Max_A = max(Max_A, A[i]);
            Max[bel[x]] = Max_A;
            return ;
        }
        else {
            if(Max[bel[x]] && Max[bel[x]] != 1) {
                for(int i = x; i <= bel[x] * block; i ++) {
                    int C = A[i] - (int) sqrt(A[i]);
                    W[bel[x]] -= C;
                    A[i] = (int) sqrt(A[i]);
                }
                LL Max_A = 0;
                for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) Max_A = max(Max_A, A[i]);
                Max[bel[x]] = Max_A;
            }
            if(Max[bel[y]] && Max[bel[y]] != 1) {
                for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) {
                    int C = A[i] - (int) sqrt(A[i]);
                    W[bel[y]] -= C;
                    A[i] = (int) sqrt(A[i]);
                }
                LL Max_A = 0;
                for(int i = (bel[y] - 1) * block + 1; i <= bel[y] * block; i ++) Max_A = max(Max_A, A[i]);
                Max[bel[y]] = Max_A;
            }    
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) {
            if(!Max[i] || Max[i] == 1) continue ;
            LL Max_A = 0;
            for(int j = (i - 1) * block + 1; j <= i * block; j ++) {
                int C = A[j] - (int) sqrt(A[j]);
                W[i] -= C;
                A[j] = (int) sqrt(A[j]);
                Max_A = max(Max_A, A[j]);
            }
            Max[i] = Max_A;
        }
    }
    
    inline int Sec_A(int x, int y) {
        LL ret = 0;
        if(bel[x] == bel[y] && Max[bel[x]]) for(int i = x; i <= y; i ++) ret += A[i];
        else {
            for(int i = x; i <= bel[x] * block && Max[bel[x]]; i ++) ret += A[i];
            for(int i = (bel[y] - 1) * block + 1; i <= y && Max[bel[y]]; i ++) ret += A[i];
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) ret += W[i];
        return ret;
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1, W[bel[i]] += A[i], Max[bel[i]] = max(Max[bel[i]], A[i]);
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(!opt) Sec_G(l, r);
            else cout << Sec_A(l, r) << "
    ";
        }
        return 0;
    }

    数列分块入门 6

    https://loj.ac/problem/6282

    单点插入,单点询问

    数据随机,分块,对于每一块开动态数组,插入 + 查询比较容易实现

    如果数据不随机,就有可能加到同一块中的数较多,影响效率

    这样可以进行一定的插入操作之后重新分块

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    
    using namespace std;
    const int N = 1e5 + 10;
    
    int A[N << 1], n;
    vector <int> Vec[350];
    int block, bel[N];
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline void Ins(int x, int a) {
        int now_size(0), Whi;
        for(int i = 1; ; i ++) {
            int Size = Vec[i].size();
            now_size += Size;
            if(now_size >= x) {
                Whi = i;
                x -= (now_size - Size);
                break;
            }
        }
        Vec[Whi].insert(Vec[Whi].begin() + x - 1, a);
    }
    
    inline int Poi_A(int x) {
        int Whi_, now_size(0);
        for(int i = 1; ; i ++) {
            int Size = Vec[i].size();
            now_size += Size;
            if(now_size >= x) {
                int iii = x - (now_size - Size);
                return Vec[i][iii - 1];
            }
        }
    }
    
    int main() {
        n = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) A[i] = read();
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1;
        for(int i = 1; i <= n; i ++) Vec[bel[i]].push_back(A[i]);
        int T = n;
    
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(!opt) Ins(l, r);
            else cout << Poi_A(r) << endl;
        }
        return 0;
    }

    数列分块入门 7

    https://loj.ac/problem/6283

    区间乘法,区间加法,单点询问

    先乘后加,乘的时候相应的加法标记也要乘

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    
    using namespace std;
    const int N = 1e5 + 10;
    const int Mod = 1e4 + 7;
    
    #define LL long long
    
    LL A[N], Mul[N], Add[N], bel[N];
    int n, cnt, block;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0, f = 1; char c = gc;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc;}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline void Sec_Add(int x, int y, int w) {
        if(bel[x] == bel[y]) {
            for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) A[i] = (A[i] * Mul[bel[x]] + Add[bel[x]]);
            Add[bel[x]] = 0; Mul[bel[x]] = 1;
            for(int i = x; i <= y; i ++) A[i] += w, A[i] %= Mod;
            return ;
        } else {
            for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) A[i] = (A[i] * Mul[bel[i]] + Add[bel[i]]) % Mod;
            Add[bel[x]] = 0; Mul[bel[x]] = 1;
            for(int i = x; i <= bel[x] * block; i ++) A[i] += w, A[i] %= Mod;
            for(int i = (bel[y] - 1) * block + 1; i <= bel[y] * block; i ++) A[i] = (A[i] * Mul[bel[i]] + Add[bel[i]]) % Mod;
            Add[bel[y]] = 0; Mul[bel[y]] = 1;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] += w, A[i] %= Mod;
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] += w, Add[i] %= Mod;
    }
    
    inline void Sec_Mul(int x, int y, int w) {
        if(bel[x] == bel[y]) {
            for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) A[i] = (A[i] * Mul[bel[i]] + Add[bel[i]]) % Mod;
            Add[bel[x]] = 0; Mul[bel[x]] = 1;
            for(int i = x; i <= y; i ++) A[i] = (A[i] * w) % Mod; 
            return ;
        } else {
            for(int i = (bel[x] - 1) * block + 1; i <= bel[x] * block; i ++) A[i] = (A[i] * Mul[bel[i]] + Add[bel[i]]) % Mod;
            Add[bel[x]] = 0; Mul[bel[x]] = 1;
            for(int i = x; i <= bel[x] * block; i ++) A[i] = (A[i] * w) % Mod;
            for(int i = (bel[y] - 1) * block + 1; i <= bel[y] * block; i ++) A[i] = (A[i] * Mul[bel[i]] + Add[bel[i]]) % Mod;
            Add[bel[y]] = 0; Mul[bel[y]] = 1;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] = (A[i] * w) % Mod; 
        }
        for(int i = bel[x] + 1; i < bel[y]; i ++) Add[i] = (Add[i] * w) % Mod, Mul[i] = (Mul[i] * w) % Mod; 
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) A[i] = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1, Mul[i] = 1;
        int T = n;
        while(T --) {
            int opt = read(), l = read(), r = read(), c = read();
            if(opt == 0) Sec_Add(l, r, c);
            else if(opt == 1) Sec_Mul(l, r, c);
            else cout << (A[r] * Mul[bel[r]] + Add[bel[r]]) % Mod << "
    ";
        }
        return 0;
    }

     数列分块入门 8

    https://loj.ac/problem/6284

    暴力

    区间修改没有什么难度,这题难在区间查询比较奇怪,因为权值种类比较多,似乎没有什么好的维护方法。

    模拟一些数据可以发现,询问后一整段都会被修改,几次询问后数列可能只剩下几段不同的区间了。

    我们思考这样一个暴力,还是分块,维护每个分块是否只有一种权值,区间操作的时候,对于同权值的一个块就O(1)统计答案,否则暴力统计答案,并修改标记,不完整的块也暴力。

    这样看似最差情况每次都会耗费O(n)的时间,但其实可以这样分析:

    假设初始序列都是同一个值,那么查询是O(√n),如果这时进行一个区间操作,它最多破坏首尾2个块的标记,所以只能使后面的询问至多多2个块的暴力时间,所以均摊每次操作复杂度还是O(√n)。

    换句话说,要想让一个操作耗费O(n)的时间,要先花费√n个操作对数列进行修改。

    初始序列不同值,经过类似分析后,就可以放心的暴力啦。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
        
    using namespace std;
    const int N = 1e5 + 10;
    
    int bel[N], A[N], bec[N];
    int n;
    int block;
    
    #define gc getchar()
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    int Sec_A(int x, int y, int c) {
        int ret(0);
        if(bel[x] == bel[y]) {
            if(bec[bel[x]] == c) ret = y - x + 1;
            else if(bec[bel[x]] == -1) for(int i = x; i <= y; i ++) if(A[i] == c) ret ++;
            if(~ bec[bel[x]]) for(int i = (bel[x] - 1) * block + 1; i < x; i ++) A[i] = bec[bel[x]];
            if(~ bec[bel[x]]) for(int i = y + 1; i <= bel[x] * block; i ++) A[i] = bec[bel[x]];
            for(int i = x; i <= y; i ++) A[i] = c;
            bec[bel[x]] = -1;
        } else {
            if(bec[bel[x]] == c) ret += bel[x] * block - x + 1;
            else if(bec[bel[x]] == -1) for(int i = x; i <= bel[x] * block; i ++) if(A[i] == c) ret ++;
            if(bec[bel[y]] == c) ret += y - ((bel[y] - 1) * block);
            else if(bec[bel[y]] == -1) for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) if(A[i] == c) ret ++;
            for(int i = bel[x] + 1; i < bel[y]; i ++) {
                if(bec[i] == c) ret += block;
                else if(bec[i] == -1)
                    for(int j = (i - 1) * block + 1; j <= i * block; j ++)
                        if(A[j] == c) ret ++;
            }
            if(~ bec[bel[x]]) for(int i = (bel[x] - 1) * block + 1; i < x; i ++) A[i] = bec[bel[i]];
            for(int i = x; i <= bel[x] * block; i ++) A[i] = c;
            bec[bel[x]] = -1;
            for(int i = (bel[y] - 1) * block + 1; i <= y; i ++) A[i] = c;
            if(~ bec[bel[y]]) for(int i = y + 1; i <= bel[y] * block; i ++) A[i] = bec[bel[i]];
            bec[bel[y]] = -1;
            for(int i = bel[x] + 1; i < bel[y]; i ++) bec[i] = c;
        }
        return ret;
    }
    
    int main() {
        n = read();
        for(int i = 1; i <= n; i ++) bec[i] = -1;
        for(int i = 1; i <= n; i ++) A[i] = read();
        block = sqrt(n);
        for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / block + 1;
        int T = n;
        while(T --) {
            int l = read(), r = read(), c = read();
            cout << Sec_A(l, r, c) << "
    ";
        }
        return 0;
    }

     数列分块入门 9

    https://loj.ac/problem/6285

    区间众数查询

    陈立杰区间众数解题报告

    #include<map>
    #include<set>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define mod 10007
    #define pi acos(-1)
    #define inf 0x7fffffff
    #define ll long long
    using namespace std;
    ll read() {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    int n,blo,id;
    int v[50005],bl[50005];
    int f[505][505];
    map<int,int>mp;
    int val[50005],cnt[50005];
    vector<int>ve[50005];
    void pre(int x) {
        memset(cnt,0,sizeof(cnt));
        int mx=0,ans=0;
        for(int i=(x-1)*blo+1; i<=n; i++) {
            cnt[v[i]]++;
            int t=bl[i];
            if(cnt[v[i]]>mx||(cnt[v[i]]==mx&&val[v[i]]<val[ans]))
                ans=v[i],mx=cnt[v[i]];
            f[x][t]=ans;
        }
    }
    int query(int l,int r,int x) {
        int t=upper_bound(ve[x].begin(),ve[x].end(),r)-lower_bound(ve[x].begin(),ve[x].end(),l);
        return t;
    }
    int query(int a,int b) {
        int ans,mx;
        ans=f[bl[a]+1][bl[b]-1];
        mx=query(a,b,ans);
        for(int i=a; i<=min(bl[a]*blo,b); i++) {
            int t=query(a,b,v[i]);
            if(t>mx||(t==mx&&val[v[i]]<val[ans]))ans=v[i],mx=t;
        }
        if(bl[a]!=bl[b])
            for(int i=(bl[b]-1)*blo+1; i<=b; i++) {
                int t=query(a,b,v[i]);
                if(t>mx||(t==mx&&val[v[i]]<val[ans]))ans=v[i],mx=t;
            }
        return ans;
    }
    int main() {
        n=read();
        blo=200;
        for(int i=1; i<=n; i++) {
            v[i]=read();
            if(!mp[v[i]]) {
                mp[v[i]]=++id;
                val[id]=v[i];
            }
            v[i]=mp[v[i]];
            ve[v[i]].push_back(i);
        }
        for(int i=1; i<=n; i++)bl[i]=(i-1)/blo+1;
        for(int i=1; i<=bl[n]; i++)pre(i);
        for(int i=1; i<=n; i++) {
            int a=read(),b=read();
            if(a>b)swap(a,b);
            printf("%d
    ",val[query(a,b)]);
        }
        return 0;
    }

    分块算法小结:

      暴力算法

      时间复杂度可以

      空间允许

      优美

  • 相关阅读:
    Leetcode 257. 二叉树的所有路径
    Leetcode 1306. 跳跃游戏 III
    Leetcode 编程中好用的一些C++用法
    Leetcode 96. 不同的二叉搜索树
    Leetcode 892. 三维形体的表面积
    Leetcode 219. 存在重复元素 II
    Leetcode 5281. 使结果不超过阈值的最小除数
    springboot多租户设计
    MAC电脑修改Terminal以及vim高亮显示
    基于springboot搭建的web系统架构
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8976890.html
Copyright © 2020-2023  润新知