BZOJ3343 教主的魔法 二分法+分块
题意:给定一个数列,维护:1、[L,R]之间所有的数+=W 2、求[L,R]中大于等于C的数的数量
题解:更新用add标记,头尾俩块暴力重构;查询将每个块排序然后二分找。
#include <cmath> #include <ctime> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXS=1000+2; struct BLOCK{ int a[MAXS],b[MAXS],add; }block[MAXS]; int N,M,S; char s; void Update(int l,int r,int x){ if((l-1)%S){ int p=(l-1)/S+1; for(int i=l-S*(p-1);i<=S && i<=r-(p-1)*S;i++) block[p].a[i]+=x; for(int i=1;i<=S;i++) block[p].b[i]=block[p].a[i]; sort(block[p].b+1,block[p].b+S+1); l=p*S+1; } while(l+S-1<=r) block[l/S+1].add+=x,l+=S; if(r%S){ int p=l/S+1;r-=S*(p-1); for(int i=1;i<=r;i++) block[p].a[i]+=x; for(int i=1;i<=S;i++) block[p].b[i]=block[p].a[i]; sort(block[p].b+1,block[p].b+S+1); } } int Find(int p,int l,int r,int c){ c-=block[p].add; int m=(l+r)>>1; while(l<=r){ if(block[p].b[m]<c) l=m+1; else r=m-1; m=(l+r)>>1; } return S-l+1; } int Query(int l,int r,int c){ int ret=0; if((l-1)%S){ int p=(l-1)/S+1; for(int i=l-S*(p-1);i<=r-S*(p-1) && i<=S;i++) if(block[p].a[i]>=c-block[p].add) ret++; l=p*S+1; } while(l+S-1<=r) ret+=Find(l/S+1,1,S,c),l+=S; if(r%S){ int p=l/S+1; for(int i=1;i<=r-S*(p-1);i++) if(block[p].a[i]>=c-block[p].add) ret++; } return ret; } int main(){ memset(block,0X7F,sizeof(block)); block[1].add=0; cin >> N >> M,S=(int)sqrt(N); for(int i=1,j=1,k=1;i<=N;i++,j++){ cin >> block[k].a[j],block[k].b[j]=block[k].a[j]; if(j==S || i==N){ sort(block[k].b+1,block[k].b+j+1); k++,j=0,block[k].add=0; } } N=(N%S?N/S+1:N/S); for(int i=1,l,r,x;i<=M;i++){ cin >> s; cin >> l >> r >> x; if(s=='M') Update(l,r,x); if(s=='A') cout << Query(l,r,x) << endl; } return 0; }