先贴个old hand的博客
https://blog.youkuaiyun.com/u012469987/article/details/41357377
讲的很详细,主要看里面的lazy。
贴个题
A Simple Problem with Integers
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.
Sample Input
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
Sample Output
4
55
9
15
题意:给你n个数, m个操作,Q操作是询问区间【ai,aj】的和, C是把区间【ai,aj】的值全都都加上 t;
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#define N 110000
using namespace std;
#define ll long long
struct node
{
ll lazy, sum;
int le; 这里的le表示节点的区间长度。
} e[N*5];
ll build(int l, int r, int num) 这个是建树很简单,初始lazy为0;
{
int mid = (l+r)/2;
e[num].lazy = 0;
e[num].le = r-l+1;
if(l == r) return e[num].sum = a[l];
return e[num].sum = build(mid+1, r, num*2+1) + build(l, mid, num*2);
}
void pushdown(int num) 这个是lazy下放,也就是更新,把lazy下放给左右孩子,
{ 并且让左右孩子都加上lazy × le(孩子的区间长度)的值。
if(e[num].lazy)
{
e[num*2].lazy += e[num].lazy;
e[num*2+1].lazy += e[num].lazy;
e[num*2].sum += e[num].lazy * e[num*2].le;
e[num*2+1].sum += e[num].lazy * e[num*2+1].le;
e[num].lazy = 0; 本节点的lazy已经下放给孩子了,就没了,为0;
}
}
下放的关键是每次查询到有lazy的节点就更新,不查询到不动他。
ll makesum(int i, int j, int l, int r, int num) 这个是求区间和。为求i,j在l,r区间的和。
{
if(i <= l && j >= r) 所求的i,j的区间已经包括l,r直接就是l,r区间的sum。
return e[num].sum;
int mid = (r+l)/2;
pushdown(num);
ll ans = 0;
if(mid >= i)
ans+=makesum(i, j, l, mid, num*2);
if(mid < j)
ans+=makesum(i, j, mid+1, r, num*2+1);
return ans;
}
void chang(int i, int j, int x, int l, int r, int num) 更新,让i,j在l,r区间的值都加r,num为这个节点编号。
{
if(i<=l && j >= r) 所更新的i,j的区间已经包括l,r。
{
e[num].lazy += x;
e[num].sum += x*e[num].le;
return;
}
int mid = (l+r)/2;
pushdown(num);
if(mid >= i)
chang(i, j, x, l, mid, num*2);
if(mid < j)
chang(i, j, x, mid+1, r, num*2+1);
e[num].sum = e[num*2].sum + e[num*2+1].sum;
}
int main()
{
int n, m;
memset(a, 0, sizeof(a));
memset(e, 0, sizeof(e));
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
scanf("%lld",&a[i]);
}
build(1, n, 1);
string s;
while(m--)
{
cin >> s;
int i, j, t;
if(s == "C")
{
scanf("%d%d%d",&i, &j, &t);
chang(i, j, t, 1, n, 1);
}
else if(s == "Q")
{
scanf("%d%d",&i, &j);
printf("%lld\n",makesum(i, j, 1, n, 1));
}
}
return 0;
}
完了-------------