P2801 教主的魔法

P2801 教主的魔法

大致题意

给一个长度为\(n\)的序列\(a_i\),有\(m\)次操作,操作分为两种\(:\)

  • 将区间\([l,r]\)上的所有数加上\(c\)

  • 查询区间\([l,r]\)中小于\(c\)的数的个数

分析

数列分块入门题

对于查询操作,若\(l,r\)在同一个块内,直接暴力查询

反之,若不在同一个块内,则答案由三部分组成:以\(l\)开头的不完整块,以\(r\)结尾的不完整块,中间一连串连续的完整快

由于要查询大于等于\(c\)的值,考虑开一个数组\(t\)存块中元素排序后的值

对于不完整块,直接暴力查询

对于完整块,在\(t\)数组中二分查找\(c\)的值即可

修改操作也同理

\(l,r\)在同一个块内,直接暴力查询

若不在一个块内,对于不完整块直接暴力修改,并更新该块在\(t\)数组中的值

对于完整块,使用类似于\(lazttag\)的方式保存即可


复杂度

预处理时,需对每个块内元素进行一次排序,复杂度为\(O(nlogn)\)

查询时,每次至多暴力修改\(2\sqrt n\)个元素,对\(\sqrt n\)个块内二分或排序,复杂度为\(O(\sqrt n +\sqrt n log\sqrt n )\)

总复杂度为\(O(\sqrt n +\sqrt n log\sqrt n + nlogn)\)

code
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
const int MAXN = 1000010;
int a[MAXN],belong[MAXN],t[MAXN],n,m,st[MAXN],ed[MAXN],tag[MAXN];
void sort(int x){
	for(int i=st[x];i<=ed[x];i++) t[i] = a[i];
	sort(t+st[x],t+ed[x]+1);
}
void add(int l,int r,int val){
	int x = belong[l],y = belong[r];
	if(x==y){
	  for(int i=l;i<=r;i++) a[i]+=val;
	  sort(x);
	  return;
	}
	for(int i=l;i<=ed[x];i++) a[i]+=val;
	for(int i=st[y];i<=r;i++) a[i]+=val;
	for(int i=x+1;i<y;i++) tag[i]+=val;
	sort(x);
	sort(y);
}
int query(int l,int r,int val){
	int res = 0;
	int x = belong[l],y = belong[r];
	if(x==y){
		for(int i=l;i<=r;i++) if(a[i]+tag[x]>=val) res++;
		return res;
	}
	for(int i=l;i<=ed[x];i++) if(a[i]+tag[x]>=val) res++;
	for(int i=st[y];i<=r;i++) if(a[i]+tag[y]>=val) res++;
	for(int i=x+1;i<y;i++)  res += ed[i]-(lower_bound(t+st[i],t+ed[i]+1,val-tag[i])-t)+1;
	return res;
}
int main(){
	n = read(),m = read();
	for(int i=1;i<=n;i++) a[i]=read();
	int size  = sqrt(n);
	for(int i=1;i<=size;i++){
		st[i] = (i-1)*size+1,ed[i] = i*size;
	}
	ed[size] = n;
	for(int i=1;i<=size;i++){
		for(int j=st[i];j<=ed[i];j++){
			belong[j] = i;
		}
		sort(a+st[i],a+ed[i]+1);
		sort(i);
	}
	for(int i=1;i<=m;i++){
		char op;
		int a,b,c;
		cin>>op;
		a = read(),b=read(),c=read();
		if(op=='A'){
			cout<<query(a,b,c)<<endl;
		}
		else{
			add(a,b,c);
		}
	}
}

参考资料

块状数组 - OI Wiki

posted @ 2020-09-19 13:38  xcxc82  阅读(127)  评论(0编辑  收藏  举报