线段树区间更新+题目

给你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 AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+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 

 

你可能感兴趣的:(编程)