码迷,mamicode.com
首页 > 其他好文 > 详细

[洛谷P2801]教主的魔法

时间:2017-10-27 15:46:46      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:std   数组   c++   scan   等于   inline   span   ace   font   

题目大意:有n个数,q个操作。操作有两种:①把一段区间所有数加上p;②查询一段区间内大于等于p的元素的个数。

解题思路:询问次数少,可以用分块解决。

将所有数分成$\sqrt{n}$块,对每一块进行排序。

用a数组存原来的数列,b数组存排完序后的数列。

查询时,对左右两个块中的数据暴力查询,中间的由于整块访问并排完序,直接二分查找即可。

修改数据时,对左右两个块中的数据暴力修改,并且更新b数组(重新排序),对中间的,由于相对大小不变,直接打上标记即可。

修改时,最多对两个块进行排序,时间复杂度$O(\sqrt{n}\log_2\sqrt{n})$。

查询时,最多对所有块都进行二分查找,时间复杂度$O(\sqrt{n}\log_2\sqrt{n})$。

故总时间复杂度$O(q\sqrt{n}\log_2\sqrt{n})$。

C++ Code:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cctype>
using namespace std;
int a[1000005],b[1000005];
int n,q,size,l[1005],r[1005],blocks,add[1005],inbk[1000005];
char s[4];
inline int readint(){
    char c=getchar();
    for(;!isdigit(c);c=getchar());
    int d=0;
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^‘0‘);
    return d;
}
void chan(int blk){
	for(int i=l[blk];i<=r[blk];++i)
	b[i]=a[i];
	sort(b+l[blk],b+r[blk]+1);
}
int main(){
	n=readint();q=readint();
	size=(int)(sqrt(n)+0.00000001);
	blocks=0;
	l[1]=1;
	for(int i=1;i<=n;++i){
		a[i]=b[i]=readint();
		inbk[i]=blocks+1;
		if(i%size==0){
			r[++blocks]=i;
			l[blocks+1]=i+1;
		}
	}
	if(n%size)
	r[++blocks]=n;
	for(int i=1;i<=blocks;++i)
	sort(b+l[i],b+r[i]+1);
	memset(add,0,sizeof add);
	while(q--){
		scanf("%s",s);
		if(s[0]==‘M‘){
			int L=readint(),R=readint(),p=readint();
			if(L>R)L^=R^=L^=R;
			int lft=inbk[L],rgt=inbk[R];
			if(lft==rgt){
				for(int i=L;i<=R;++i)a[i]+=p;
				chan(lft);
			}else{
				for(int i=lft+1;i<rgt;++i)add[i]+=p;
				for(int i=L;i<=r[lft];++i)a[i]+=p;
				for(int i=l[rgt];i<=R;++i)a[i]+=p;
				chan(lft);
				chan(rgt);
			}
		}else{
			int L=readint(),R=readint(),p=readint(),ans=0;
			int lft=inbk[L],rgt=inbk[R];
			if(lft==rgt){
				for(int i=L;i<=R;++i)
				if(a[i]+add[lft]>=p)++ans;
			}else{
				for(int i=lft+1;i<rgt;++i)
				ans+=r[i]-(lower_bound(b+l[i],b+r[i]+1,p-add[i])-b-1);
				for(int i=L;i<=r[lft];++i)
				if(a[i]+add[lft]>=p)++ans;
				for(int i=l[rgt];i<=R;++i)
				if(a[i]+add[rgt]>=p)++ans;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

 

[洛谷P2801]教主的魔法

标签:std   数组   c++   scan   等于   inline   span   ace   font   

原文地址:http://www.cnblogs.com/Mrsrz/p/7742626.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!