洛谷P2801 教主的魔法
- 题意:区间加,然后查询区间内大于a的数.
- 做法:对于每个块维护一个它的排好序的序列,每次查找lowerbound就星,不是整块的就暴力。
然后注意每次加的时候不是整块的那部分原有顺序会被破坏,暴力再排序就是。
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 1000005 3 4 using namespace std; 5 int a[nmax],b[nmax],p[nmax],add[nmax]={0}; 6 int n,bn,m,q; 7 8 inline void reset(int x){ //把块x的排序 9 int r=bn*x,l=bn*(x-1)+1; 10 for (int i=l; i<=r; i++) b[i]=a[i]; 11 sort(b+l,b+r+1); 12 } 13 14 void build(){ 15 cin>>n>>q; 16 bn=sqrt(n); 17 m=n/bn; 18 if(n%bn) m++; 19 for (int i=0; i<n; i++){ 20 scanf("%d",&a[i+1]); 21 p[i+1]=i/bn+1; 22 } 23 for (int i=1; i<=m; i++) reset(i); 24 } 25 26 inline int find(int l,int r,int x){ 27 int ans=0; 28 for (int i=l; i<=r; i++) if(a[i]>=x) ans++; 29 return ans; 30 } 31 32 inline void update(int l,int r,int x){ 33 if(p[l]==p[r]) { 34 for (int i=l; i<=r; i++) a[i]+=x; 35 reset(p[l]); 36 return; 37 } 38 for (int i=p[l]+1; i<p[r]; i++) add[i]+=x; 39 for (int i=l; i<=p[l]*bn; i++) a[i]+=x; 40 reset(p[l]); 41 for (int i=(p[r]-1)*bn+1; i<=r; i++) a[i]+=x; 42 reset(p[r]); 43 } 44 45 inline int query(int l,int r,int x){ 46 int ta,ans=0; 47 if(p[l]==p[r]) return find(l,r,x-add[ p[l] ]); 48 for (int i=p[l]+1; i<p[r]; i++) { 49 int r=bn*i,l=bn*(i-1)+1; 50 ta=lower_bound(b+l,b+r+1,x-add[i])-(b+l); 51 ans+=bn-ta; 52 } 53 ans+=find( l,p[l]*bn,x-add[ p[l] ]); 54 ans+=find( (p[r]-1)*bn+1 ,r,x-add[ p[r] ]); 55 return ans; 56 } 57 58 int main(){ 59 freopen("testdata.in","r",stdin); 60 build(); 61 char in[10]; 62 int l,r,t; 63 for (int i=0; i<q; i++) { 64 scanf("%s%d%d%d",in,&l,&r,&t); 65 if(in[0]=='M') update(l,r,t); 66 else printf("%d\n",query(l,r,t)); 67 } 68 return 0; 69 }
- 基本上照着hzwer学长打的,orz感谢这么好的分块教程。