题目
题目链接
题意
- 修改:将一个区间内所有的数+C。
- 查询:查询一个区间内>C的数字有多少个。
题解
很经典的分快算法题目。
将数列分块以后,对块内的元素进行排序。
- 当我们要做修改操作的时候:遇到要修改的完整的块的时候,我们给它在addmark数组的相应的位置+C,标记为我对整个区间做了一个修改操作,有点类似于带lazy标记的线段树的操作。当要修改的部分区间不是完整的块的时候,我们检查这部分区间所在的块的addmark有没有被标记,如果有就对这个块整个进行更新操作,然后把addmark清零,并且暴力把这部分区间的元素+C。时间复杂度为O(n‾√+n‾√∗logn‾√))O(n+n∗logn))。
- 当我们遇到查询操作的时候:当我们要查询的部分区间不属于完整的块的时候,如果块的addmark被标记过了,那么更新这个块,然后再暴力查询这个“部分区间”。当我们要查询的区间属于完整的块的时候,由于这个区间是有序的,我们只需要使用二分搜索结合addmark,就可以确定出该块内>C的元素有多少个。时间复杂度O(n‾√+n‾√∗logn‾√))O(n+n∗logn))。
因此总的时间复杂度就是:O((n‾√+n‾√∗logn‾√)∗m)O((n+n∗logn)∗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;
}