返回顶部

分块板子

预处理

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  无敌の暗黑魔王  阅读(16)  评论(0编辑  收藏  举报