给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。
需要用到线段树的,update:成段增减,query:区间求和
介绍Lazy思想:lazy思想,记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。
在此通俗的解释我理解的Lazy意思,比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,它的节点标记为rt,这时tree[rt].l== a && tree[rt].r == b 这时我们可以一步更新此时rt节点的sum[rt]的值,sum[rt] += c* (tree[rt].r - tree[rt].l + 1),注意关键的时刻来了,如果此时按照常规的线段树的update操作,这时候还应该更新rt子节点的sum[]值,而Lazy思想恰恰是暂时不更新rt子节点的sum[]值,到此就return,直到下次需要用到rt子节点的值的时候才去更新,这样避免许多可能无用的操作,从而节省时间
代码核心部分:
long long int push( long long int i )
{
if( s[i].lazy )
{
s[2*i].lazy += s[i].lazy;
s[2*i+1].lazy += s[i].lazy;
s[2*i].sum += s[i].lazy*s[2*i].len;
s[2*i+1].sum += s[i].lazy*s[2*i+1].len;
s[i].lazy = 0;
}
}
例题
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
大意 : Q为查询区间 C 为在【a,b】每一个数加上c
#include
#include
#include
#include
#include
#include
using namespace std;
char str[10];
long long int n,q;
struct node
{
long long int l; ///左端点
long long int r; ///右端点
long long int len; ///区间长度
long long int lazy; 懒惰标记
long long int sum; 该节点的值
}s[400005];
long long int build( long long int i, long long int l, long long int r ) 建树
{
long long int x;
s[i].l = l;
s[i].r = r;
s[i].len = r-l+1;
if( s[i].l == s[i].r )
{
scanf("%lld", &x);
s[i].sum += x;
return 1;
}
else
{
long long int mid = ( l+r )/2;
build( 2*i, l, mid);
build( 2*i+1, mid+1, r );
s[i].sum = s[2*i].sum + s[2*i+1].sum;
}
}
long long int push( long long int i )
{
if( s[i].lazy ) 若有标记
{
s[2*i].lazy += s[i].lazy; 将其标记向下传递
s[2*i+1].lazy += s[i].lazy;
s[2*i].sum += s[i].lazy*s[2*i].len; 更新子节点的sum
s[2*i+1].sum += s[i].lazy*s[2*i+1].len;
s[i].lazy = 0;
}
}
long long int add(long long int i, long long int a, long long int b,long long int x )
{
if( s[i].l == a && s[i].r == b ) .//该区间为要查询的范围 更新其sum 作lazy标记 不再向下更新
{
s[i].sum += ( b-a+1)*x;
s[i].lazy += x;
return 1;
}
//if( s[i].l == s[i].r ) return 1;
push( i );
long long int mid = ( s[i].l + s[i].r)/2;
if( b <= mid)
{
add( 2*i, a,b, x);
}
else
if( a > mid )
{
add( 2*i+1, a,b, x);
}
else
{
add( 2*i, a, mid ,x );
add( 2*i+1, mid+1, b ,x);
}
s[i].sum = s[2*i].sum +s[2*i+1].sum;
}
long long int query ( long long int i , long long int a,long long int b )
{
if( s[i].l == a && s[i].r == b )
{
return s[i].sum;
}
push( i );
long long int mid = ( s[i].l+s[i].r)/2;
if( mid >= b )
{
return query( 2*i, a, b);
}
else
if( mid