E. 田田的算数题 2014新生暑假个人排位赛08
时间限制 10000 ms
内存限制 65536 KB
题目描述
焦级长和田田玩算数。焦级长给田田一个数列ai,然后问田田第i项到第j项的数的和。
田田随手写了个简单的数据结构就搞定了。于是焦级长打算加大题目难度。
焦级长又添加了一个操作,即从第i项到第j项都按顺序加上一个等差数列的项
如从第2项到第4项加入一个首项为1,公差为3的等差数列即第2项+1,第3项+4,第4项+7,以此类推
于是田田写了半天又WA又T还RE了一炮,终于来求救你让你来写个程序帮他
输入格式
第一行为case数T
每个case第一行输入n,m,表示有数列长为n,有m个操作
之后n个数为ai即数列的初始数
之后m行为m个操作
第一个操作为插入
为1,l,r,x,d
1表示插入操作,l,r为数列的[l,r]会进行操作,等差数列的首项为x,公差为d
第二个操作为查询和
为2,l,r
2表示查询,l,r为求和的范围,即求al到ar的数列的和
T<=10
n,m<=10^5
ai,x<10^5,|d|<=100;
输出格式
每个查询输出一个值
输入样例
1
6 9
1 2 3 4 5 6
2 1 4
2 1 6
1 1 4 1 0
2 2 5
1 2 4 1 1
2 1 4
2 2 4
2 1 5
2 2 6
输出样例
10
21
17
20
18
25
29
思路:其实有了首项与公差,整个区间的和就知道了。只需要两个域记录这个区间的首项与公差即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define maxn 1000005
//#define LOCAL
using namespace std;
int n,m;
long long a[maxn],sum[maxn<<2],sumo[maxn<<2],addv[maxn<<2],setv[maxn<<2];
void build(int o,int L,int R)
{
//printf("L=%d R=%d\n",L,R);
int lc=o<<1,rc=(o<<1)+1;
addv[o]=setv[o]=0;
if(L==R){sum[o]=sumo[o]=a[L];return;}
int M=(L+R)>>1;
build(lc,L,M);
build(rc,M+1,R);
sum[o]=sum[lc]+sum[rc];
//printf("0 o=%d L=%d R=%d sum=%I64d setv1=%I64d setv2=%I64d\n",o,L,R,sumv[o],setv1[o],setv2[o]);
}
void maintain(int o,int L,int R)
{
int lc=o<<1,rc=(o<<1)+1;
sum[o]=0;
if(L==R)sum[o]=sumo[o];
if(L<R)sum[o]=sum[lc]+sum[rc];
sum[o]+=addv[o]*(R-L+1);
sum[o]+=(R-L+1)*(R-L)/2*setv[o];
}
void update(int o,int L,int R,int l,int r,long long v,long long d)
{
//printf("1 o=%d L=%d R=%d l=%d r=%d v=%I64d d=%I64d\n",o,L,R,l,r,v,d);
int lc=o<<1,rc=(o<<1)+1;
if(l<=L&&R<=r)
{
addv[o]+=(v+(L-l)*d);
setv[o]+=d;
}
else
{
int M=(L+R)>>1;
if(l<=M)update(lc,L,M,l,r,v,d);
if(M<r)update(rc,M+1,R,l,r,v,d);
}
maintain(o,L,R);
//printf("2 o=%d L=%d R=%d l=%d r=%d v=%I64d d=%I64d\n",o,L,R,l,r,v,d);
//printf("sum=%I64d addv=%I64d setv=%I64d\n",sum[o],addv[o],setv[o]);
}
long long query(int o,int L,int R,int l,int r,long long add,long long set)
{
long long ret=0;
int lc=o<<1,rc=(o<<1)+1;
//printf("3 o=%d L=%d R=%d l=%d r=%d add=%I64d set=%I64d\n",o,L,R,l,r,add,set);
if(l<=L&&R<=r)
{
//printf("sumo=%I64d\n",sum[o]);
ret+=(sum[o]+add*(R-L+1)+(R-L)*(R-L+1)/2*set);
}
else
{
int M=(L+R)>>1;
if(l<=M)ret+=query(lc,L,M,l,r,add+addv[o],set+setv[o]);
if(M<r)
{
//printf("3.5 o=%d L=%d R=%d l=%d r=%d add=%I64d set=%I64d\n",o,L,R,l,r,add,set);
//printf("3.5 o=%d M+1=%d R=%d l=%d r=%d add=%I64d set=%I64d\n",o,M+1,R,l,r,add,set);
//printf("3.5 %I64d %I64d\n",addv[o],setv[o]);
ret+=query(rc,M+1,R,l,r,add+addv[o]+(M-L+1)*(set+setv[o]),set+setv[o]);
}
}
//printf("4 o=%d L=%d R=%d l=%d r=%d add=%I64d set=%I64d\n",o,L,R,l,r,add,set);
//printf("4 ret=%I64d\n",ret);
return ret;
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif // LOCAL
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
long long kind,l,r,x,d;
for(int i=1;i<=m;i++)
{
scanf("%lld",&kind);
if(kind==1)
{
scanf("%lld%lld%lld%lld",&l,&r,&x,&d);
update(1,1,n,l,r,x,d);
}
if(kind==2)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",query(1,1,n,l,r,0,0));
}
}
}
return 0;
}