教主的魔法

题目:教主的魔法

题目大意:给定一个数列,修改和查询两种操作,修改每次给定一个区间,区间的所有元素都加上一个给定值,查询询问一段区间的数权值大于等于给定值的数有多少个。

做法:这是一道分块的好题,首先先进行分块,然后每个块暴力修改,暴力排序,然后求值时暴力二分即可,反正就是一道暴力的题目

代码如下:

#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值