题目链接:http://codevs.cn/problem/1082/
题目描述 Description
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
pascal选手请不要使用readln读入
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3
1
2
3
2
1 2 3 2
2 2 3
样例输出 Sample Output
9
数据范围及提示 Data Size & Hint
数据范围
1<=n<=200000
1<=q<=200000
树状数组模板,区间修改,区间查询。
区间修改-区间查询的原理:
区间修改,区间查询:
引入一个函数:sigma(a,i)表示a数组的前i项和
引入一个差分数组,c[i]=a[i]-a[i-1];
因此:a[i]=sigma(c,i);
修改r~l的值:
c[l]=c[l]+x,c[r+1]=c[r+1]+(-x);即可
sum(1,k)表示区间1-k的和。
则sum(1,k)=c1(1)+( c1(1)+c1(2) )+( c1(1)+c1(2)+c1(3) )+
...+(c1(1)+c1(2)+c1(3)+...+c1(k)).
打开多项式,合并:
sum(1,k)=k*( c1(1)+c1(2)+...+c1(k) )-( 0*c1(1)+1*c1(2)+2*c1(3)+...+(k-1)*c1(k) )。
因此分成两个数组,建立两个树状数组,
分别为:
tree1 = k*( c1(1)+c1(2)+...+c1(k) ) 前缀和
tree1[]=c1(1),c1(2),c1(3), ... ,c1(k);
/*-------*/
tree2 = ( 0*c1(1)+1*c1(2)+2*c1(3)+...+(k-1)*c1(k) ) i的前缀和
tree2[]=c1(1)*0,c1(2)*1,c1(3)*2, ... ,(k-1)*c1(k);
用第一个减去第二个就是区间查询的结果了
知道原理直接套用模板就行了:
ac:
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 1000000007
#define clean(a,b) memset(a,b,sizeof(a))// 水印
ll tree1[200100],tree2[200100];
ll sum[200100];
int n,q;
/*--------模板-----------*/
int lowbit(int i)
{
return i&(-i);
}
void updata(ll i,ll x,ll* tree)
{
while(i<=n)
{
tree[i]=tree[i]+x;
i=i+lowbit(i);
}
}
ll Query(ll i,ll *tree)
{
ll res=0;
while(i>0)
{
res=res+tree[i];
i=i-lowbit(i);
}
return res;
}
/*------------模板---------------*/
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>sum[i];
sum[i]=sum[i]+sum[i-1];
}
cin>>q;
for(int i=1;i<=q;++i)
{
int oper;
cin>>oper;
if(oper==1)
{
int a,b,x;
cin>>a>>b>>x;
updata(a,x,tree1);//增加的数组
updata(b+1,-x,tree1);
updata(a,x*a,tree2);//减少的数组
updata(b+1,-(b+1)*x,tree2);
}
else
{
// sum[r]-sum[l-1];
// (r+1)*Query(r,tree1)-l*Query(l-1,tree1);
// -(Query(r,tree2)-Query(l-1,tree2));
int a,b;
cin>>a>>b;
ll res=sum[b]-sum[a-1];
res=res+(b+1)*Query(b,tree1)-a*Query(a-1,tree1);
res=res-(Query(b,tree2)-Query(a-1,tree2));
cout<<res<<endl;
}
}
}