[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\n",query(ql,qr,w));
	} 
	return 0;
}

总结###

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

posted @ 2017-10-20 17:09  小飞淙的云端  阅读(214)  评论(0编辑  收藏  举报