返回顶部

分块板子

预处理

void init(){
clean();
scanf("%lld",&n);
for(i=1;i<=n;i++)scanf("%lld",&a[i]);
sq=sqrt(n);
for(i=1;i<=sq;i++){
st[i]=n/sq(i-1)+1;
ed[i]=n/sq
i;
}
ed[sq]=n;
for(i=1;i<=sq;i++){
for(j=st[i];j<=ed[i];j++)belong[j]=i,sum[i]+=a[j];
size[i]=ed[i]-st[i]+1;
}
}

多测清空

void clean(){
memset(sum,0,sizeof sum);//块的区间和
memset(mark,0,sizeof mark);//块标记
memset(st,0,sizeof st);//块的头
memset(ed,0,sizeof ed);//块尾
memset(belong,0,sizeof belong);//各点所在块编号
memset(a,0,sizeof a);//数组
memset(size,0,sizeof size);//各个块的元素总数
}

单点加减

void ad(int x,int y){
a[x]+=y;
sum[belong[x]]+=y;
}

区间求和

int Sum(int l,int r){
int ans=0;
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++)ans+=(a[i]+mark[belong[l]]);
}else{
for(int i=l;i<=ed[belong[l]];i++)ans+=(a[i]+mark[belong[l]]);
for(int i=st[belong[r]];i<=r;i++)ans+=(a[i]+mark[belong[r]]);
for(int i=belong[l]+1;i<belong[r];i++)ans+=(sum[i]+mark[i]*size[i]);
}
return ans;
}

区间修改

void add(int l,int r,int val){
if(belong[l]==belong[r]){
for(int i=l;i<=r;i++){
a[i]+=val;
sum[belong[l]]+=val;
}
}else {
for(int i=l;i<=ed[belong[l]];i++){
a[i]+=val;
sum[belong[l]]+=val;
}
for(int i=st[belong[r]];i<=r;i++){
a[i]+=val;
sum[belong[r]]+=val;
}
for(int i=belong[l]+1;i<belong[r];i++)mark[i]+=val;
}
}

教主的魔法

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N=1e6+100;
int mark[N],belong[N],st[N],ed[N],n,m,v[N];
int x,y,c;
vector<int>a[N];
void one(int x){
	a[x].clear();
	for(int i=st[x];i<=ed[x];i++)a[x].push_back(v[i]);
	sort(a[x].begin(),a[x].end());
}
void add(int l,int r,int c){
	if(belong[l]==belong[r]){
		for(int i=l;i<=r;i++)v[i]+=c;
		one(belong[l]);
	}else{
		for(int i=l;i<=ed[belong[l]];i++)v[i]+=c;
		one(belong[l]);
		for(int i=st[belong[r]];i<=r;i++)v[i]+=c;
		one(belong[r]);
		for(int i=belong[l]+1;i<belong[r];i++)mark[i]+=c;
	}
}
void Sum(int l,int r,int c){
	int ans=0;
	if(belong[l]==belong[r]){
		for(int i=l;i<=r;i++){
			if(v[i]+mark[belong[l]]>=c)ans++;
		}
	}else{
		for(int i=l;i<=ed[belong[l]];i++)if(v[i]+mark[belong[l]]>=c)ans++;
		for(int i=st[belong[r]];i<=r;i++)if(v[i]+mark[belong[r]]>=c)ans++;
		for(int i=belong[l]+1;i<belong[r];i++){
			int o=lower_bound(a[i].begin(),a[i].end(),c-mark[i])-a[i].begin();
			ans+=(a[i].size()-o);
		}
	}
	printf("%lld\n",ans);
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&v[i]);
	int sq=sqrt(n);
	for(int i=1;i<=sq;i++){
		st[i]=n/sq*(i-1)+1;
		ed[i]=n/sq*i;
	}
	ed[sq]=n;
	for(int i=1;i<=sq;i++){
		for(int j=st[i];j<=ed[i];j++){
			belong[j]=i;
			a[i].push_back(v[j]);
		}
		sort(a[i].begin(),a[i].end());
	}
	while(m--){
		char ch;
		scanf(" %s%lld%lld%lld",&ch,&x,&y,&c);
		if(ch=='M')add(x,y,c);
		else if(ch=='A')Sum(x,y,c);
	}
	return 0;
}
$\quad \ $用$vector$存一下各块,并在每次操作后将其排序,保证其有序以便二分查找某元素(虽然我懒得打二分直接用lower_bound). $\quad \$ $vector$真的太好用了(doge),排序都不用想下标,直接 a.begin() 和 a.end() 就行。
posted @ 2024-04-15 20:23  无敌の暗黑魔王  阅读(59)  评论(0)    收藏  举报