• 分块学习笔记


    先上大佬博客

    也不知道为什么我先学的莫队

    生动形象的分块(三层的树)

    假设我们总共的序列长度为n,然后我们把它切成n−−√n块,然后把每一块里的东西当成一个整体来看,

    现在解释几个本文用到的术语:

    完整块:被操作区间完全覆盖的块

    不完整块:操作区间不完全覆盖的块

    然后我们先看看怎么得出答案:

      1.对于完整的块,我们希望有个东西能直接找出这整个块的和,于是每个块要维护这个块的所有元素的和。   

        .对于不完整块,因为元素比较少(最多有  总数n /  块数 = n−−√n 个) 这时候当n=1000000的时候最多有1000个,对比一下,我们可以直接暴力扫这个小块统计答案,

        .小技巧:如果这个不完整块被覆盖的长度>块维护的长度的一半,何不用这个块的和-没有被覆盖的元素的值呢?

      2.这里,我们换种思路,记录一个lazy   标记(为什么用lazy,因为我很懒),表示整个块被加上过多少了,

        .对于完整块,我们直接lazy+=加上的数x,块内的和ans+=x*元素个数(因为每个元素都被加上了x)

        .对于不完整块,直接暴力修改就好了,顺便可以把lazy标记清了。

    题目列表

    #6277. 数列分块入门 1

    操作:区间加法,单点查值

    #include <bits/stdc++.h>
    using namespace std;
    inline long long read() {  //读入优化
        long long x = 0;
        long long f = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -f;
            c = getchar();
        }
        while (c <= '9' && c >= '0') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * f;
    }
    int n;
    int m;
    int opt, l, r, c;
    int z[500521];    //原数组
    int pos[500521];  //存储每个点所在的块
    int tag[500521];  //标记数组
    void modify(int l, int r, int c) {
        if (pos[l] == pos[r])  //如果在同一个块内直接暴力修改
            for (int i = l; i <= r; i++) z[i] += c;
        else {
            for (int i = l; i <= pos[l] * m; i++)  //修改左边不在一整块中的部分
                z[i] += c;
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++)  //标记每个块需要加上的值
                tag[i] += c;
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++)  //修改右边不在一整块中的部分
                z[i] += c;
        }
    }
    int main() {
        n = read();
        m = sqrt(n);
        for (int i = 1; i <= n; i++) z[i] = read();
        int bnum = ceil((double)n / m);  //上取整函数
        for (int i = 1; i <= bnum; i++)
            for (int j = (i - 1) * m + 1; j <= i * m; ++j) pos[j] = i;
        for (int i = 1; i <= n; i++) {
            opt = read();
            if (opt == 0) {
                l = read();
                r = read();
                c = read();
                modify(l, r, c);
            }
            if (opt == 1) {
                l = read();
                r = read();
                c = read();
                printf("%d
    ",z[r] + tag[pos[r]]);  //最后输出的值就是该点的值加上该点所在块的标记值(即需要加上的值)
            }
        }
        return 0;
    }

    数列分块入门2:

    操作:区间加法,询问区间内小于某个值 xxx 的元素个数

    似乎并没有什么区别,主要就是多了一个reset函数,emm另外, lower_bound的特性利用也很重要

    #include <bits/stdc++.h>
    using namespace std;
    inline long long read() {
        long long x = 0;
        long long f = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -f;
            c = getchar();
        }
        while (c <= '9' && c >= '0') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * f;
    }
    long long n, m;
    long long opt, l, r, c;
    long long z[5211314];
    long long pos[5211314];
    long long tag[5211314];
    vector<long long> v[1314];
    void reset(long long x) {
        v[x].clear();  //清空该块内的元素
        for (long long i = (x - 1) * m + 1; i <= x * m; i++) v[x].push_back(z[i]);
        sort(v[x].begin(), v[x].end());
    }
    void modify(long long l, long long r, long long c) {  //修改函数
        if (pos[l] == pos[r]) {                           //在同一块内
            for (long long i = l; i <= r; i++)
                z[i] += c;  // 排序只是在vector中有序,因为是原数组修改,所以需要清空此块重新插入进行排序
            reset(pos[l]);
        } else {
            for (long long i = l; i <= pos[l] * m; i++)
                z[i] += c;  // 排序只是在vector中有序,因为是原数组修改,所以需要清空此块重新插入进行排序
            reset(pos[l]);
            for (long long i = pos[l] + 1; i <= pos[r] - 1; i++)
                tag[i] += c;  //对块进行标记时,区间加法并不会影响序列次序,所以只需要标记块
            for (long long i = (pos[r] - 1) * m + 1; i <= r; i++)
                z[i] += c;  // 排序只是在vector中有序,因为是原数组修改,所以需要清空此块重新插入进行排序
            reset(pos[r]);
        }
    }
    
    long long query(long long l, long long r, long long f) {
        long long ans = 0;
        if (pos[l] == pos[r]) {
            for (long long i = l; i <= r; i++)
                if (z[i] + tag[pos[i]] < f)
                    ans++;
            return ans;
        } else {
            for (long long i = l; i <= pos[l] * m; i++)
                if (z[i] + tag[pos[i]] < f)
                    ans++;
            for (long long i = pos[l] + 1; i <= pos[r] - 1; i++) {
                long long t = f - tag[i];
                // lowe_bound返回第一个大于或等于t的位置,减去begin得到区间内元素个数
                ans += lower_bound(v[i].begin(), v[i].end(), t) - v[i].begin();
            }
            for (long long i = (pos[r] - 1) * m + 1; i <= r; i++)
                if (z[i] + tag[pos[i]] < f)
                    ans++;
        }
        return ans;
    }
    int main() {
        n = read();
        m = sqrt(n);
        //预处理每个点所在的快
        int bnum = ceil((double)n / m);  //上取整函数
        for (int i = 1; i <= bnum; i++)
            for (int j = (i - 1) * m + 1; j <= i * m; ++j) pos[j] = i;
        for (long long i = 1; i <= n; i++) {
            z[i] = read();
            v[pos[i]].push_back(z[i]);
        }
        //利用sort把每个块内的数据排好序 begin和end 代表所要排序的范围即整个v[i][~]‘’
        for (long long i = 1; i <= pos[n]; i++) sort(v[i].begin(), v[i].end());
        for (long long i = 1; i <= n; i++) {
            opt = read();
            if (opt == 0) {
                l = read();
                r = read();
                c = read();
                modify(l, r, c);
            }
            if (opt == 1) {
                l = read();
                r = read();
                c = read();
                printf("%lld
    ", query(l, r, c * c));
            }
        }
        return 0;
    }

     

    数列分块入门 3

    改一改查询操作就好了。

    #include <bits/stdc++.h>
    using namespace std;
    inline long long read() {
        long long x = 0;
        long long f = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -f;
            c = getchar();
        }
        while (c <= '9' && c >= '0') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * f;
    }
    long long n, m;
    long long opt, l, r, c;
    long long z[5211314];
    long long pos[5211314];
    long long tag[5211314];
    vector<long long> v[1314];
    void reset(long long x) {
        v[x].clear();  //清空该块内的元素
        for (long long i = (x - 1) * m + 1; i <= x * m; i++) v[x].push_back(z[i]);
        sort(v[x].begin(), v[x].end());
    }
    void modify(long long l, long long r, long long c) {  //修改函数
        if (pos[l] == pos[r]) {                           //在同一块内
            for (long long i = l; i <= r; i++)
                z[i] += c;  
            reset(pos[l]);
        } else {
            for (long long i = l; i <= pos[l] * m; i++)
                z[i] += c;  // 排序只是在vector中有序,因为是原数组修改,所以需要清空此块重新插入进行排序
            reset(pos[l]);
            for (long long i = pos[l] + 1; i <= pos[r] - 1; i++)
                tag[i] += c;  //对块进行标记时,区间加法并不会影响序列次序,所以只需要标记块
            for (long long i = (pos[r] - 1) * m + 1; i <= r; i++)
                z[i] += c;  // 排序只是在vector中有序,因为是原数组修改,所以需要清空此块重新插入进行排序
            reset(pos[r]);
        }
    }
    
    long long query(long long l, long long r, long long f) {
        long long ans = -1;
        if (pos[l] == pos[r]) {
            for (long long i = l; i <= r; i++)
                if (z[i] + tag[pos[i]] < c)
                    ans=max(ans,z[i] + tag[pos[i]]);
            for (long long i = pos[l] + 1; i <= pos[r] - 1; i++) {
                long long t = c - tag[i];
                long long size=lower_bound(v[i].begin(), v[i].end(), t) - v[i].begin() ;
                if(size>=l&&size<=r)ans = max(v[i][size-1]+tag[i],ans);
            }
            return ans;
        } else {
            for (long long i = l; i <= pos[l] * m; i++)
                if (z[i] + tag[pos[i]] < c)
                    ans=max(ans,z[i] + tag[pos[i]]); 
            for (long long i = (pos[r] - 1) * m + 1; i <= r; i++)
                if (z[i] + tag[pos[i]] < c)
                    ans=max(ans,z[i] + tag[pos[i]]); 
            for (long long i = pos[l] + 1; i <= pos[r] - 1; i++) {
                long long t = c - tag[i];
                long long size=lower_bound(v[i].begin(), v[i].end(), t) - v[i].begin() ;
                if(size>=1)ans = max(v[i][size-1]+tag[i],ans);
            }
        }
        return ans;
    }
    int main() {
        n = read();
        m = sqrt(n);
        int bnum = ceil((double)n / m);
        for (int i = 1; i <= bnum; i++)
            for (int j = (i - 1) * m + 1; j <= i * m; ++j) pos[j] = i;
        for (long long i = 1; i <= n; i++) {
            z[i] = read();
            v[pos[i]].push_back(z[i]);
        }
        for (long long i = 1; i <= pos[n]; i++) sort(v[i].begin(), v[i].end());
        for (long long i = 1; i <= n; i++) {
            opt = read();
            if (opt == 0) {
                l = read();
                r = read();
                c = read();
                modify(l, r, c);
            }
            if (opt == 1) {
                l = read();
                r = read();
                c = read();
                printf("%lld
    ", query(l, r, c));
            }
        }
        return 0;
    }

    数列分块入门4:

    操作:区间加法,区间求和
    操作还是不完整的块暴力,完整的标记区间,不过需要预处理出每个块的和。
    修改时,修改每个点或块的同时,需要修改每个块的和

    ps:注意数据范围数组需要开long long(简直毒瘤)

    #include<bits/stdc++.h> 
    using namespace std;
    long long n,m;
    const int maxn = 5211314;
    long long pos[maxn],tag[maxn],sum[maxn],z[maxn];
    long long opt, l, r, c;
    long long ans;
    inline long long read(){//读入优化
        long long x = 0; long long f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void modify(long long l, long long r, long long c) {
        if (pos[l] == pos[r]) {
            for (int i = l; i <= r; i++) {
                z[i] +=c;
                sum[pos[i]]+=c ;
            }
        } else {
            for (int i = l; i <= pos[l] * m; i++) {
                z[i] +=c;
                sum[pos[i]]+=c ;
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                z[i] +=c;
                sum[pos[i]]+=c ;
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                tag[i]+=c;
                sum[i]+=m*c; 
            }
        }
    }
    long long query(long long l, long long r, long long c) {
        ans = 0;
        if (pos[l] == pos[r]) {
            for (int i = l; i <= r; i++) {
                ans += z[i] + tag[pos[l]];
            }
            return ans % c;
        } else {
            for (int i = l; i <= pos[l] * m; i++) {
                ans += z[i] + tag[pos[i]];
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                ans += z[i] + tag[pos[i]];
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                ans += sum[i];
            }
            return ans % c;
        }
    }
    int main(){
        n = read();
        m = sqrt(n);
        int bnum=ceil((double)n/m);//上取整函数 
        for(int i = 1; i <= bnum; i++) 
            for(int j=(i-1)*m+1;j<=i*m;++j)pos[j] = i;
        for(int i = 1; i<=n; i++) {z[i] = read();sum[pos[i]]+=z[i];}
        for(int i = 1; i<=n; i++){
             opt=read();
             if(opt == 0){
                l = read();
                r = read();
                c = read();
                modify(l,r,c);
             }
             if(opt == 1){
                l = read();
                r = read();
                c = read();
                printf("%lld
    ",query(l,r,c+1));
             }
        }
        return 0;
    }

    数列分块入门5:

    操作区间开方,区间求和

    对于完整块,最多修改5次,因为前面分析过,修改5次肯定都为1了,所以上限为O(5n)。

    对于不完整块,每次修改最多触及2次,所以上限为O(2n√n) 期间枚举完整块时间上限为O(n√n)。

    上代码(我太爱loj的自动缩进了)

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5211314;
    int read() {
        int x = 0, k = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                k = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * k;
    }
    int opt, l, r, c, m, n;
    int z[N], s[N], pos[N];
    bool v[N];
    void change(int l, int r) {
        if (pos[l] == pos[r]) {
            for (int i = l; i <= r; i++) {
                s[pos[i]] -= z[i];
                z[i] = sqrt(z[i]);
                s[pos[i]] += z[i];
            }
            return;
        } else {
            for (int i = l; i <= pos[l] * m; i++) {
                s[pos[i]] -= z[i];
                z[i] = sqrt(z[i]);
                s[pos[i]] += z[i];
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                s[pos[i]] -= z[i];
                z[i] = sqrt(z[i]);
                s[pos[i]] += z[i];
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                if (!v[i]) {
                    v[i] = 1;
                    for (int j = m * (i - 1) + 1; j <= m * i; j++) {
                        s[i] -= z[j];
                        z[j] = sqrt(z[j]);
                        s[i] += z[j];
                        if (z[j] > 1)
                            v[i] = 0;
                    }
                }
            }
        }
    }
    int query(int l, int r) {
        int ans = 0;
        if (pos[l] == pos[r]) {
            for (int i = l; i <= r; i++) {
                ans += z[i];
            }
            return ans;
        } else {
            for (int i = l; i <= pos[l] * m; i++) {
                ans += z[i];
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                ans += z[i];
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                ans += s[i];
            }
            return ans;
        }
    }
    int main() {
        n = read(), m = sqrt(n);
        int bnum = ceil((double)n / m);
        for (int i = 1; i <= bnum; i++) {
            for (int j = m * (i - 1) + 1; j <= i * m; j++) {
                pos[j] = i;
            }
        }
        for (int i = 1; i <= n; i++) {
            z[i] = read();
            s[pos[i]] += z[i];
        }
        for (int i = 1; i <= n; i++) {
            opt = read();
            if (opt == 0) {
                l = read();
                r = read();
                c = read();
                change(l, r);
            }
            if (opt == 1) {
                l = read();
                r = read();
                c = read();
                printf("%lld
    ", query(l, r));
            }
        }
    }
     
    
    数列分块入门6:
    操作:单点插入,单点询问
    
    用强大的vector解决这个问题
    #include<bits/stdc++.h> 
    using namespace std;
    const int N=5211314;
    long long read(){//读入优化
        long long x = 0; long long f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int a[N]; 
    int n,m,lx;
    vector<int>v[1005];
    void mer() {
        n=0;
        for(int i=1;i<=m+1;i++){
            if(v[i].empty())break;
            for(int j=0;j<v[i].size();j++){
                a[++n]=v[i][j]; 
            } 
            v[i].clear(); 
        }
    } 
    void div(){
        m=sqrt(n);
        int bnum=ceil((double)n/m);//上取整函数 
        for(int i = 1; i <= bnum; i++) 
            for(int j=(i-1)*m+1;j<=i*m;++j)v[i].push_back(a[j]);
    } 
    int query(int l){
        int bnum=ceil((double)n/m);
        for(int i=1;i<=bnum;i++){
            if(l>v[i].size())l-=v[i].size();
            else return v[i][l-1]; 
        } 
    } 
    void ins( int l, int c ){
        for ( int i = 1; i <= m + 1; ++i ){
            if ( l > v[i].size() ) l -= v[i].size();
            else{
                v[i].insert( v[i].begin() + l - 1, c );//插入~
                if ( v[i].size() > 10 * m ) mer(), div();//重排
                return;
            }
        }
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        div();
        lx=n;
        for(int i=1;i<=lx;i++){
            int opt,l,r,c;
            opt=read();
            if(opt==0){
               l=read(),r=read(),c=read(); 
               ins(l,r); 
            } else{
               l=read(),r=read(),c=read(); 
               printf("%d
    ",query(r));
            } 
        } 
        return 0;
    } 
     

    数列分块入门7:

    给出一个长为  的数列,以及  个操作,操作涉及区间乘法,区间加法,单点询问。

    参考线段树的思想,将每一个点的值表示为a[i]=(a[i]*tagmul[pos[i]]+tadadd[pos[i]])%p,]照着前面的改就好了。

    #include <bits/stdc++.h>
    using namespace std;
    #define N 5211314
    const int p = 10007;
    int n, m;
    int a[N], pos[N], tagmul[N], tagadd[N];
    int read() {
        int x = 0, k = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                k = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * k;
    }
    void push(int l) {
        for (int i = (l - 1) * m + 1; i <= l * m; i++) {
            a[i] = (a[i] * tagmul[l] + tagadd[l]) % p;
        }
        tagmul[l] = 1, tagadd[l] = 0;
    }
    void add(int l, int r, int c) {
        if (pos[l] == pos[r]) {
            push(pos[l]);
            for (int i = l; i <= r; i++) {
                a[i] = (a[i] + c) % p;
            }
            return;
        } else {
            push(pos[l]), push(pos[r]);
            for (int i = l; i <= pos[l] * m; i++) {
                a[i] = (a[i] + c) % p;
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                a[i] = (a[i] + c) % p;
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                tagadd[i] = (tagadd[i] + c) % p;
            }
        }
    }
    void mul(int l, int r, int c) {
        if (pos[l] == pos[r]) {
            push(pos[l]);
            for (int i = l; i <= r; i++) {
                a[i] = (a[i] * c) % p;
            }
            return;
        } else {
            push(pos[l]), push(pos[r]);
            for (int i = l; i <= pos[l] * m; i++) {
                a[i] = (a[i] * c) % p;
            }
            for (int i = (pos[r] - 1) * m + 1; i <= r; i++) {
                a[i] = (a[i] * c) % p;
            }
            for (int i = pos[l] + 1; i <= pos[r] - 1; i++) {
                tagadd[i] = (tagadd[i] * c) % p;
                tagmul[i] = (tagmul[i] * c) % p;
            }
        }
    }
    int main() {
        n = read();
        m = sqrt(n);
        int num = ceil((double)n / m);
        for (int i = 1; i <= num; i++) {
            for (int j = (i - 1) * m + 1; j <= i * m; j++) {
                pos[j] = i;
            }
        }
        for (int i = 1; i <= pos[n]; ++i) tagadd[i] = 0, tagmul[i] = 1;
        for (int i = 1; i <= n; i++) {
            a[i] = read();
        }
        for (int i = 1; i <= n; i++) {
            int opt = read(), l = read(), r = read(), c = read();
            switch (opt) {
                case 0:
                    add(l, r, c);
                    break;
                case 1:
                    mul(l, r, c);
                    break;
                case 2:
                    printf("%d
    ", (a[r] * tagmul[pos[r]] + tagadd[pos[r]]) % p);
                    break;
            }
        }
        return 0;
    }

    数列分块入门8:

    操作:操作涉及区间询问等于一个数 c 的元素,并将这个区间的所有元素改为 c

    #include<bits/stdc++.h>
    using namespace std;
    #define N 5211314
    int n,m;
    int a[N],pos[N];
    int v[N];
    int read() {
        int x = 0, k = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                k = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * k;
    }
    void pushdown(int x){
        if(v[x]==-1) return ;
        for(int i=(x-1)*m+1;i<=min(n,x*m);i++) a[i]=v[x];
        v[x]=-1;    
    }
    int query(int l,int r,int c){
        int ans=0;
        pushdown(pos[l]);
        if(pos[l]==pos[r]){
           for(int i=l;i<=min(r,pos[l]*m);i++)    {
               if(a[i]==c) ans++;
               else a[i]=c; 
            }
        } 
        else {
            pushdown(pos[r]);
            for(int i=l;i<=min(r,pos[l]*m);i++)    {
               if(a[i]==c) ans++;
               else a[i]=c; 
            }
            for(int i=(pos[r]-1)*m+1;i<=r;i++) {
                if(a[i]==c) ans++;
                else a[i]=c;
            }
            for(int i=pos[l]+1;i<=pos[r]-1;i++){
            if(v[i]==-1){
                for(int j=(i-1)*m+1;j<=i*m;j++)
                    if(a[j]==c) ans++;
            }
            if(v[i]==c) ans+=m;
            v[i]=c;
            }
        } 
        return ans;
    } 
    int main(){
        n=read();m=sqrt(n);
        int num=ceil((double)n/m);
        for(int i=1;i<=num;i++){
            v[i]=-1; 
            for(int j=(i-1)*m+1;j<=i*m;j++){
                pos[j]=i; 
            } 
        }
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++){
            int l=read(),r=read(),c=read();
            printf("%d
    ",query(l,r,c)); 
        } 
        return 0; 
    } 

    数列分块入门9

    静态,区间求众数。

    毒瘤题目我交了三页多

    数据真是大的一批,样例也是水的一批怎么改都对。唉。毒瘤啊

    #include<bits/stdc++.h>
    using namespace std;
    #define N 5211314
    int n,m;
    int a[N],pos[N];
    int v[N];
    int read() {
        int x = 0, k = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-')
                k = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            x = x * 10 + c - '0';
            c = getchar();
        }
        return x * k;
    }
    void pushdown(int x){
        if(v[x]==-1) return ;
        for(int i=(x-1)*m+1;i<=min(n,x*m);i++) a[i]=v[x];
        v[x]=-1;    
    }
    int query(int l,int r,int c){
        int ans=0;
        pushdown(pos[l]);
        if(pos[l]==pos[r]){
           for(int i=l;i<=min(r,pos[l]*m);i++)    {
               if(a[i]==c) ans++;
               else a[i]=c; 
            }
        } 
        else {
            pushdown(pos[r]);
            for(int i=l;i<=min(r,pos[l]*m);i++)    {
               if(a[i]==c) ans++;
               else a[i]=c; 
            }
            for(int i=(pos[r]-1)*m+1;i<=r;i++) {
                if(a[i]==c) ans++;
                else a[i]=c;
            }
            for(int i=pos[l]+1;i<=pos[r]-1;i++){
            if(v[i]==-1){
                for(int j=(i-1)*m+1;j<=i*m;j++)
                    if(a[j]==c) ans++;
            }
            if(v[i]==c) ans+=m;
            v[i]=c;
            }
        } 
        return ans;
    } 
    int main(){
        n=read();m=sqrt(n);
        int num=ceil((double)n/m);
        for(int i=1;i<=num;i++){
            v[i]=-1; 
            for(int j=(i-1)*m+1;j<=i*m;j++){
                pos[j]=i; 
            } 
        }
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++){
            int l=read(),r=read(),c=read();
            printf("%d
    ",query(l,r,c)); 
        } 
        return 0; 
    } 

    分块完结。撒花~~。

    作者:wilxx
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    查找——图文翔解HashTree(哈希树)
    比較JS合并数组的各种方法及其优劣
    PTA 是否同一棵二叉搜索树(25 分)
    PTA 最大子列和问题(10 分)
    PTA PAT排名汇总(25 分)
    PTA PAT排名汇总(25 分)
    PTA 说反话-加强版(20 分)(字符串处理)
    PTA 说反话-加强版(20 分)(字符串处理)
    Tarjan模版(链式向前星表示方法)
    Tarjan模版(链式向前星表示方法)
  • 原文地址:https://www.cnblogs.com/wilxx/p/11681351.html
Copyright © 2020-2023  润新知