题目描述
你有N个整数,A1,A2,...,AN。 你需要处理两种操作。 一种操作是在给定间隔中为每个数字添加一些给定数字。 另一种是要求给定间隔中的数字总和。
输入
第一行包含两个数字N和Q.1≤N,Q≤100000。
第二行包含N个数字,A1,A2,...,AN的初始值。 -1000000000≤AI≤1000000000。
接下来的Q行中的每一行代表一个操作。
“C a b c”表示将C添加到Aa,Aa + 1,...,Ab中的每一个。 -10000≤c≤10000。
“Q a b”表示查询Aa,Aa + 1,...,Ab的总和。
输出
你需要回到Q个询问,每个询问一行。
样例输入
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
样例输出
4 55 9 15
题解
#include<iostream>
using namespace std;
const int maxn=1e5+10;
#define ll long long
ll a[maxn],sum[maxn*4],lazy[maxn*4];//要开四倍空间
void pushdown(int rt,int len)
{
if(lazy[rt])//不为0表示这个区间被修改了
{
lazy[2*rt]+=lazy[rt];
lazy[2*rt+1]+=lazy[rt];
sum[2*rt]+=(len-len/2)*lazy[rt];
sum[2*rt+1]+=(len/2)*lazy[rt];
lazy[rt]=0;//要记得归0
}
}
ll query(int x,int y,int l,int r,int rt)//查询
{
ll ans=0;
if(x<=l&&y>=r)//如果当前的区间被要查询的区间包含,sum就直接取
return sum[rt];
pushdown(rt,r-l+1);
int mid=(l+r)/2;
if(x<=mid)
ans+=query(x,y,l,mid,2*rt);
if(y>mid)
ans+=query(x,y,mid+1,r,2*rt+1);
return ans;
}
void update(int x,int y,int l,int r,int rt,ll z)//更新
{
if(x<=l&&y>=r)
{
lazy[rt]+=z;
sum[rt]+=(r-l+1)*z;
return;
}
pushdown(rt,r-l+1);//懒标记下传
int mid=(l+r)/2;
if(x<=mid)
update(x,y,l,mid,2*rt,z);
if(y>mid)
update(x,y,mid+1,r,2*rt+1,z);
sum[rt]=sum[2*rt]+sum[2*rt+1];
}
void build(int l,int r,int rt)//编号rt节点包含的区间是[l,r]
{
lazy[rt]=0;//初始化为0
if(l==r)
{
sum[rt]=a[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,2*rt);
build(mid+1,r,2*rt+1);
sum[rt]=sum[2*rt]+sum[2*rt+1];
}
int main()
{
char s[10];
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,n,1);
while(m--)
{
int a,b;
scanf("%s%d%d",s,&a,&b);
if(s[0]=='Q')
printf("%lld\n",query(a,b,1,n,1));
else
{
ll c;
scanf("%lld",&c);
update(a,b,1,n,1,c);
}
}
return 0;
}