题目:教主的魔法
题目大意:给定一个数列,修改和查询两种操作,修改每次给定一个区间,区间的所有元素都加上一个给定值,查询询问一段区间的数权值大于等于给定值的数有多少个。
做法:这是一道分块的好题,首先先进行分块,然后每个块暴力修改,暴力排序,然后求值时暴力二分即可,反正就是一道暴力的题目
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
using namespace std;
int n,Q,x,y,z,block,num;
int a[1000005],b[1000005],mark[1000005],belong[1000005],l[1000005],r[1000005];
void chance(int x)
{
int left1=l[x]; int right1=r[x];
for (int i=left1;i<=right1;i++) b[i]=a[i];
sort(b+left1,b+right1+1);
}
int find(int x,int lim)
{
int left1=l[x]; int right1=r[x];
int endd=right1;
while (left1<=right1){
int mid=(left1+right1)/2;
if (b[mid]<lim) left1=mid+1;
else right1=mid-1;
}
return endd-left1+1;
}
void change(int x,int y,int z)
{
if (belong[x]==belong[y]){
if (mark[belong[x]]) for (int i=l[belong[x]];i<=r[belong[x]];i++) a[i]=a[i]+mark[belong[x]];
mark[belong[x]]=0;
for (int i=x;i<=y;i++) a[i]=a[i]+z;
chance(belong[x]);
return;
}
for (int i=x;i<=r[belong[x]];i++) a[i]=a[i]+z;
for (int i=l[belong[y]];i<=y;i++) a[i]=a[i]+z;
chance(belong[x]); chance(belong[y]);
for (int i=belong[x]+1;i<belong[y];i++) mark[i]=mark[i]+z;
return;
}
int sum(int x,int y,int lim)
{
int ans=0;
if (belong[x]==belong[y]){
for (int i=x;i<=y;i++) if (a[i]+mark[belong[x]]>=lim) ans++;
return ans;
}
for (int i=x;i<=r[belong[x]];i++) if (a[i]+mark[belong[x]]>=lim) ans++;
for (int i=l[belong[y]];i<=y;i++) if (a[i]+mark[belong[y]]>=lim) ans++;
for (int i=belong[x]+1;i<belong[y];i++) ans=ans+find(i,lim-mark[i]);
return ans;
}
int main()
{
memset(mark,0,sizeof(mark));
scanf("%d%d",&n,&Q);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
block=(int)sqrt(n);
num=n/block;
if (n%block) num++;
for (int i=1;i<=num-1;i++){
l[i]=(i-1)*block+1;
r[i]=i*block;
}
l[num]=r[num-1]+1; r[num]=n;
for (int i=1;i<=n;i++) belong[i]=((i-1)/block)+1;
for (int i=1;i<=num;i++) chance(i);
while (Q--){
char ch;
cin>>ch; scanf("%d%d%d",&x,&y,&z);
if (ch=='M') change(x,y,z);
else printf("%d\n",sum(x,y,z));
}
return 0;
}