题目:传送传送~答题操作如下:
Q 操作:代表询问 a~b的区间和
C操作:代表把a~b区间所有的数据都加c
思路:用Add[ ]数组, 标记每次需要更新的值, 用到的时候往下更新,Add值为0;
一定要充分理解Add数组啊,理解了这个,就很简单了!
PS:AC代码中乘2除2写的比较乱,如果大家很难看懂的话,建议学一下二进制的乘2除2(<<1, >>1), 速度要比*2,/2快一点,嘻嘻嘻看看我总结的也可以,我觉得还挺良心的~ 移位符运算传送门~
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define Max 100005
typedef long long ll;//定义long long 一定要用typedef,嘤嘤嘤学会了
using namespace std;
ll Sum[Max<<2] = {0}, Add[Max<<2] = {0}; // <<2 代表Max乘4, 二进制写法, 速度较快,而且看起来也够高大上(手动滑稽);
void Build(ll l, ll r, ll rt)
{
if(l == r)
{
scanf("%lld", &Sum[rt]);
return ;
}
ll mid = l + ( r - l) / 2;
Build(l, mid, rt*2);
Build(mid+1, r, rt*2+1);
Sum[rt] = Sum[rt*2] + Sum[rt*2+1];//区间和;
}
void Pushdown(ll rt, ll len)
{
if(Add[rt])//如果需要更新的话;
{
Add[rt<<1] += Add[rt];
Add[rt<<1|1] += Add[rt];
Sum[rt<<1] += Add[rt] * (len - len / 2);//左区间的长度是(l+r)/2, 也就是(len-len/2);
Sum[rt<<1|1] += Add[rt] * (len>>1);
Add[rt] = 0;
}
}
void Update(ll x, ll L, ll R, ll l, ll r, ll rt)
{
if(L <= l && R >= r)
{
Sum[rt] += x * (r - l + 1);
Add[rt] += x;
return;
}
Pushdown(rt, r-l+1);
ll mid = l + (r - l) / 2;
if(L <= mid) Update(x, L, R, l, mid, rt*2);
if(R > mid) Update(x, L, R, mid+1, r, rt*2+1);//R>mid,一定要记住,我之前写的mid+1,wa了好多发,一定要记住嘤嘤嘤
Sum[rt] = Sum[rt*2] + Sum[rt*2+1];//区间和更新
}
ll QuerySum(ll L, ll R, ll l, ll r, ll rt)
{
if( L <= l && R >= r)
{
return Sum[rt];
}
Pushdown(rt, r-l+1);
ll mid = l + (r - l) / 2;
ll cnt = 0;
if(L <= mid)
cnt += QuerySum(L, R, l, mid, rt*2);
if(R > mid)
cnt += QuerySum(L, R, mid+1, r, rt*2+1);
return cnt;
}
int main()
{
ll n, q, L, R, x, ans;
char ch;
scanf("%lld%lld", &n, &q);
Build(1, n, 1);
while(q--)
{
getchar();
scanf("%c", &ch);
if(ch == 'Q')
{
scanf("%lld%lld", &L, &R);
ans = QuerySum(L, R, 1, n, 1);
printf("%lld\n", ans);
}
else if(ch == 'C')
{
scanf("%lld%lld%lld", &L, &R, &x);
Update(x, L, R, 1, n, 1);
}
}
return 0;
}