[BZOJ3343]教主的魔法

题目描述 Description###

教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给(XMYZ) 信息组每个英雄看。于是(N) 个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为(1、2、……、N)

每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间$ [L, R]$ ((1≤L≤R≤N)) 内的英雄的身高全部加上一个整数W。(虽然(L=R) 时并不符合区间的书写规范,但我们可以认为是单独增加第(L)(R) )个英雄的身高)

(CYZ) 、光哥和(ZJQ) 等人不信教主的邪,于是他们有时候会问(WD) 闭区间 ([L, R]) 内有多少英雄身高大于等于(C) ,以验证教主的魔法是否真的有效。

(WD) 巨懒,于是他把这个回答的任务交给了你。

输入描述 Input Description###

第1行为两个整数(N、Q)(Q) 为问题数与教主的施法数总和。
第2行有(N) 个正整数,第i个数代表第i个英雄的身高。
第3到第Q+2行每行有一个操作:
(1)若第一个字母为“(M) ”,则紧接着有三个数字(L)(R)(W) 。表示对闭区间 ([L, R]) 内所有英雄的身高加上(W)
(2)若第一个字母为“(A) ”,则紧接着有三个数字(L)(R)(C) 。询问闭区间 ([L, R]) 内有多少英雄的身高大于等于(C)

输出描述 Output Description###

对每个“(A) ”询问输出一行,仅含一个整数,表示闭区间 ([L, R]) 内身高大于等于(C) 的英雄数。

样例输入 Sample Input###

5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4

样例输出 Sample Output###

2
3

数据范围及提示 Data Size & Hint###

【输入输出样例说明】
原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
【数据范围】
对30%的数据,(N≤10^3)(Q≤10^3)
对100%的数据,(N≤10^6)(Q≤3000)(1≤W≤10^3)(1≤C≤10^9)

之前的一些废话###

明天周六 开心,今晚终于能睡一个好觉了!

题解###

分块,新开一个数组块内排序,修改时暴力修改两端的,并且块内排序,对于中间的块直接打标记。查询时暴力查询两端,勿忘加上标记,对于中间的块在新数组中二分出对应位置即可。

代码###

#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=1000010;
int n,q,size,A[maxn],id[maxn],tag[maxn],L[maxn],R[maxn],all,B[maxn],ql,qr,w;
char tp[4];
void bsort(int k)
{
	for(int i=L[k];i<=R[k];i++)A[i]+=tag[k],B[i]=A[i];
	tag[k]=0;
	sort(B+L[k],B+R[k]+1);
}
void update(int l,int r,int w)
{
	for(int i=l;i<=R[id[l]];i++)A[i]+=w;
	bsort(id[l]);
	if(id[l]!=id[r])
	{
		for(int i=L[id[r]];i<=r;i++)A[i]+=w;
		bsort(id[r]);
	}
	for(int i=id[l]+1;i<=id[r]-1;i++)tag[i]+=w;
}
int query(int l,int r,int w)
{
	int x=id[l],y=id[r],cnt=0;
	if(x==y){for(int i=l;i<=r;i++)cnt+=(A[i]+tag[x]>=w);return cnt;}
	cnt=0;
	for(int i=l;i<=R[x];i++)cnt+=(A[i]+tag[x]>=w);
	for(int i=L[y];i<=r;i++)cnt+=(A[i]+tag[y]>=w);
	for(int i=x+1;i<=y-1;i++)
		cnt+=(R[i]-(lower_bound(B+L[i],B+R[i]+1,w-tag[i])-B)+1);
	return cnt; 
}
int main()
{
	n=read();q=read();size=(int)sqrt(n);
	for(int i=1;i<=n;i++)A[i]=B[i]=read(),id[i]=(i-1)/size+1; 
	for(int i=1;i<=n;i+=size)L[++all]=i,R[all]=min(n,i+size-1);
	for(int i=1;i<=all;i++)bsort(i);
	while(q--)
	{
		scanf("%s",tp);
		ql=read();qr=read();w=read();
		if(tp[0]=='M')update(ql,qr,w);
		else printf("%d
",query(ql,qr,w));
	} 
	return 0;
}

总结###

分块要写出自己的风格,以此为鉴。

原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7700444.html