【LOJ#6280】数列分块4

题目大意:维护一个长度为 N 的序列,支持两种操作:区间修改、区间求和。N <= 50000

题解:在维护分块的同时,维护每个区间的和,保证在 \(O(1)\) 的时间查询答案。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

int n,q,pos[maxn],tot;
long long a[maxn];
struct node{
	int l,r;
	long long sum,add;
}b[1000];

void make_block(){
	tot=(int)sqrt(n);
	for(int i=1;i<=tot;i++)b[i].l=(i-1)*tot+1,b[i].r=i*tot;
	if(b[tot].r<n)++tot,b[tot].l=b[tot-1].r+1,b[tot].r=n;
	for(int i=1;i<=tot;i++)
		for(int j=b[i].l;j<=b[i].r;j++)
			b[i].sum+=a[j],pos[j]=i;
}

void read_and_parse(){
	n=read(),q=n;
	for(int i=1;i<=n;i++)a[i]=read();
	make_block();
}

void modify(int l,int r,int val){
	int x=pos[l],y=pos[r];
	if(x==y){
		for(int i=l;i<=r;i++)a[i]+=val;
		b[x].sum+=(r-l+1)*val;
	}else{
		for(int i=x+1;i<=y-1;i++)b[i].add+=val,b[i].sum+=(b[i].r-b[i].l+1)*val;
		for(int i=l;i<=b[x].r;i++)a[i]+=val;
		for(int i=b[y].l;i<=r;i++)a[i]+=val;
		b[x].sum+=(b[x].r-l+1)*val,b[y].sum+=(r-b[y].l+1)*val;
	}
}

long long query(int l,int r){
	int x=pos[l],y=pos[r];long long ans=0;
	if(x==y)for(int i=l;i<=r;i++)ans+=a[i]+b[x].add;
	else{
		for(int i=x+1;i<=y-1;i++)ans+=b[i].sum;
		for(int i=l;i<=b[x].r;i++)ans+=a[i]+b[x].add;
		for(int i=b[y].l;i<=r;i++)ans+=a[i]+b[y].add;
	}
	return ans;
}

void solve(){
	int opt,l,r,val;
	while(q--){
		opt=read(),l=read(),r=read(),val=read();
		if(opt==0)modify(l,r,val);
		else printf("%lld\n",query(l,r)%(val+1));
	}
}

int main(){
	read_and_parse();
	solve();
	return 0;
}
posted @ 2018-10-15 19:49  shellpicker  阅读(111)  评论(0编辑  收藏  举报