A simple problem with integer 树状数组区间查询模板题 contest 树状数组练习 T1

Description

给定一个长为n的序列,接下来m次操作,每次操作会对序列某段区间内所有数加上一个值,或是询问一段区间的和。


Input

第一行,n和m,代表序列长度为n,并有m个操作第二行有n个数字,表示序列中的每个元素接下来m行,每行形如Q a b代表查询[a,b]的区间和,或C a b c代表对[a,b]中的所有数都增加c。


Output

每行输出对应每一个查询的结果。


Hint

n,m<=100000。


Solution

同样维护一个差分数组,可以推得一段区间和的表达式就是(x+1)*sigma(d[i])-ixsigma(d[i])。用两个树状数组分别维护d[i]和d[i]xi,不过需要注意的是,维护d[i]xi的时候,修改值或者查询乘的是原本的x值而不是x+-lowbit(x)的值。

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define maxn 100005
#define lowbit(x) (x&(-x))
#define int long long
using namespace std;
int c1[maxn],c2[maxn],a[maxn],d[maxn];
int n,m,x,y,w,z;
char tmp[maxn];
void init(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
}
void doadd(int x,int dd){
	int f=x;
	while(x<=n){
		c1[x]+=dd;
		c2[x]+=f*dd;
		x+=lowbit(x);
	}
}
int dofinD(int x){
	int ans=0,f=x;
	while(x>0){
		ans+=(f+1)*c1[x]-c2[x];
		x-=lowbit(x);
	}
	return ans;
}
void set_d(){
	for(int i=1;i<=n;i++){
		d[i]=a[i]-a[i-1];
	}
	for(int i=1;i<=n;i++){
		doadd(i,d[i]);
	}
}
signed main(){
	init();
	set_d();
	for(int i=1;i<=m;i++){
		scanf("%s",tmp);
		if(tmp[0]=='Q'){
			scanf("%lld%lld",&x,&y);
			printf("%lld\n",dofinD(y)-dofinD(x-1));
		}
		else if(tmp[0]=='C'){
			scanf("%lld%lld%lld",&x,&y,&w);
			doadd(x,w);
			doadd(y+1,-w);
		}
	}
	return 0;
}
posted @ 2018-11-30 17:21  虚拟北方virtual_north。  阅读(141)  评论(0编辑  收藏  举报