You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
题意:N 个数 Q 个操作,Q a b 表示输出 [a,b] 区间内的和,C a b c 表示将 [a,b] 区间内所有的值都加上 c
思路:线段树模板题,区间更新+区间查询,注意使用 long long,emmm,最后查询的时候写成int,忘记改成longlong,wa到哭了。这里就是想记录一下,在记录lazy标记的时候,一定要先把整个区间的值都加到这个节点上。因为,你这样如果要往下更新的话,下面的区间也会这样更新,最后再pushup的时候才能得到一个准确的值,如果不当时就更改然后pushup,等查询的时候往下推状态的时候,这样是不行的,因为你不知道这部分是不是后来其中某一部分又有了修改。但在查询的时候,直接返回了,这样就产生了错误结果。(如看不懂就忽略了吧,记住下面板子就好了)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAX_SIZE = 1e5+5;
LL sum[MAX_SIZE<<2], lazy[MAX_SIZE<<2], data[MAX_SIZE];
void Push_Up(int Root)
{
sum[Root] = sum[Root<<1] + sum[Root<<1|1];
return ;
}
void Push_Down(int left, int right, int Root)
{
if(lazy[Root] == 0) return ; //如果这个节点没有修改,不需操作
int mid = (left+right)>>1;
lazy[Root<<1] += lazy[Root];
lazy[Root<<1|1] += lazy[Root];
sum[Root<<1] += lazy[Root]*(mid-left+1);
sum[Root<<1|1] += lazy[Root]*(right-mid);
lazy[Root] = 0;
return ;
}
void Build(int left, int right, int Root)
{
lazy[Root] = 0;
if(left == right)
{
sum[Root] = data[left];
return ;
}
int mid = (left+right)>>1;
Build(left, mid, Root<<1);
Build(mid+1, right, Root<<1|1);
Push_Up(Root);
return ;
}
void Section_Change(int Left, int Right, int left, int right, int Root, LL value)
{
if(Left <= left && Right >= right)
{
lazy[Root] += value;
sum[Root] += value*(right-left+1);
return ;
}
Push_Down(left, right, Root);
int mid = (left+right)>>1;
if(Left <= mid) Section_Change(Left, Right, left, mid, Root<<1, value);
if(Right > mid) Section_Change(Left, Right, mid+1, right, Root<<1|1, value);
Push_Up(Root); //一定要pushup,否则结果不对,因为下面可能会有变动
return ;
}
LL Section_Query(int Left, int Right, int left, int right, int Root)
{
if(Left <= left && Right >= right) return sum[Root];
Push_Down(left, right, Root); //先把当前节点的状态推到孩子上
int mid = (left+right)>>1;
LL ans = 0;
if(Left <= mid) ans += Section_Query(Left, Right, left, mid, Root<<1);
if(Right > mid) ans += Section_Query(Left, Right, mid+1, right, Root<<1|1);
return ans;
}
int main()
{
int N, Q;
cin >> N >> Q;
for(int i = 1; i <= N; i++) scanf("%lld", &data[i]);
Build(1, N, 1);
for(int i = 0; i < Q; i++)
{
getchar();
char op = getchar();
int a, b;
LL c;
if(op == 'C') scanf("%d%d%lld", &a, &b, &c);
else scanf("%d%d", &a, &b);
if(op == 'C') Section_Change(a, b, 1, N, 1, c);
else c = Section_Query(a, b, 1, N, 1);
if(op == 'Q') printf("%lld\n", c);
}
return 0;
}