BZOJ-3343教主的魔法+分块（大块排序二分）

ps：我在洛谷A的，BZOJ要权限；

```#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
typedef long long ll;
const int maxn = 1000009;
const int bmaxn = 1009;
int n,m;

int belong[maxn];
int num,l[bmaxn],r[bmaxn];        //块个数；i这块的左端；i这块的右端
int block;                      //块大小

void reset(int id)
{
int le = l[id],ri = r[id];
for(int i=le; i<=ri; i++)b[i] = a[i];
sort(b+le,b+ri+1);
}

void build()
{
block = sqrt(n);
num = n/block;if(n%block)num++;
for(int i=1; i<=num; i++)
l[i]=(i-1)*block+1,r[i] = i * block;
r[num] = n;
for(int i=1; i<=n; i++)
belong[i]  = (i-1)/block + 1;
for(int i=1; i <= num; i++)
reset(i);
}

void update(int lx,int rx,ll val)
{
if(belong[lx]==belong[rx])
{
for(int i=lx;i<=rx;i++)a[i]+=val;
reset(belong[lx]);
}
else
{
int li = r[belong[lx]],ri = l[belong[rx]];
for(int i = lx; i<=li; i++)a[i]+=val;
reset(belong[lx]);
for(int i = ri; i<=rx; i++)a[i]+=val;
reset(belong[rx]);
for(int i = belong[lx] + 1;i < belong[rx]; i++)add[i]+=val;
}
}

ll query(int lx,int rx,ll k)
{
ll res = 0;
if(belong[lx]==belong[rx])
{
for(int i=lx;i<=rx;i++)if(a[i] >= k - add[belong[lx]])res++;
}
else
{
int li = r[belong[lx]],ri = l[belong[rx]];
// cout<<li<<" "<<ri<<endl;
for(int i = lx; i <= li; i++) if(a[i] >= k-add[belong[lx]])res++;
for(int i = ri; i <= rx; i++) if(a[i] >= k-add[belong[rx]])res++;
for(int i = belong[lx] + 1; i<belong[rx]; i++)
{
int le = l[i],ri = r[i];
while(le <= ri)
{
int mid = (le+ri)>>1;
le = mid + 1;
else ri = mid - 1;
}
// printf("%d\n",le);
// cout<<r[i]-le+1<<endl;
res+=r[i] - le + 1;
}
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%lld", &a[i]);
build();
for(int i=1; i<=m; i++)
{
char s[20];
int x,y;
ll v;
scanf("%s%d%d%lld",s,&x,&y,&v);
if(s[0]=='M')
{
update(x,y,v);
}
else
{
ll ans = query(x,y,v);
printf("%lld\n",ans);
}
}
return 0;
}```