洛谷-P2801 教主的魔法 分块

题目

题目链接

题意

  • 修改:将一个区间内所有的数+C。
  • 查询:查询一个区间内>C的数字有多少个。

题解

很经典的分快算法题目。
将数列分块以后,对块内的元素进行排序。

  • 当我们要做修改操作的时候:遇到要修改的完整的块的时候,我们给它在addmark数组的相应的位置+C,标记为我对整个区间做了一个修改操作,有点类似于带lazy标记的线段树的操作。当要修改的部分区间不是完整的块的时候,我们检查这部分区间所在的块的addmark有没有被标记,如果有就对这个块整个进行更新操作,然后把addmark清零,并且暴力把这部分区间的元素+C。时间复杂度为 O ( n + n l o g n ) )
  • 当我们遇到查询操作的时候:当我们要查询的部分区间不属于完整的块的时候,如果块的addmark被标记过了,那么更新这个块,然后再暴力查询这个“部分区间”。当我们要查询的区间属于完整的块的时候,由于这个区间是有序的,我们只需要使用二分搜索结合addmark,就可以确定出该块内>C的元素有多少个。时间复杂度 O ( n + n l o g n ) )

因此总的时间复杂度就是: O ( ( n + n l o g n ) m )

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
#define pr(x) cout<<#x<<":"<<x<<endl
int Base = 1000;
ll a[1000007],addmark[1007],C;
int n,q,L,R;
char op;
vector<ll> vec[1007];

inline void read(ll &x){
    scanf("%lld",&x);
}

inline void read(int &x){
    scanf("%d",&x);
}

inline void read(char &c){
    scanf(" %c",&c);
}

void work(int bl){
    if(addmark[bl]){

        for(int t = bl*Base;t < (bl+1)*Base && t < n;++t){
            a[t] += addmark[bl];
        }
        for(auto &i : vec[bl]){
            i += addmark[bl];
        }

        addmark[bl] = 0;
    }
}

void buildvec(int bl){
    vec[bl].clear();
    for(int t = bl*Base;t < (bl+1)*Base && t < n;++t){
        vec[bl].push_back(a[t]);
    }
    sort(vec[bl].begin(),vec[bl].end());
}

int main(){
    scanf("%d%d",&n,&q);
    for(int i = 0;i < n;++i){
        int bl = i/Base;
        read(a[i]);
        vec[bl].push_back(a[i]);
        if((i+1)%Base == 0 || i == n-1){
            sort(vec[bl].begin(),vec[bl].end());
        }
    }


    for(int i = 0;i < q;++i){
        read(op);read(L);read(R);read(C);
        L--;R--;
        ll rep = 0;
        if(op == 'A'){
            if(L % Base != 0 && addmark[L/Base]) {
                work(L / Base);
            }

            if((R+1)%Base != 0 && addmark[R/Base]){
                work(R / Base);
            }

            int ans = 0;
            for(;L <= R && L % Base != 0;L++){
                ans += a[L] >= C;
            }

            for(;L <= R && (R+1)%Base != 0;R--){
                ans += a[R] >= C;
            }

            if(L > R){
                printf("%d\n",ans);
                continue;
            }
            int bl = L / Base;
            int br = R / Base;
            for(;bl <= br;++bl){
                auto loc = lower_bound(vec[bl].begin(),vec[bl].end(),C-addmark[bl]);
                int ad = vec[bl].size() - (loc - vec[bl].begin());
                ans += max(0,ad);
            }
            printf("%d\n",ans);

        }
        else{
            int bl,br;

            if(L % Base != 0){
                work(L / Base);
                bl = L / Base;
                for(;L <= R && L % Base != 0;++L){
                    a[L] += C;
                    //pr(L);
                    //pr(a[L]);
                }

                buildvec(bl);
            }

            if((R+1) % Base != 0){
                work(R / Base);
                br = R / Base;
                for(;L <= R && (R+1) % Base != 0;--R)
                    a[R] += C;

                buildvec(br);
            }



            if(L < R){
                bl = L / Base;
                br = R / Base;
                for(;bl <= br;++bl){
                    addmark[bl] += C;
                }
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_37517391/article/details/79794522