线段树 区间覆盖 区间增加

给你一个序列:a1 a2 a3 : : : an,有m 个操作,操作如下:

modify l r x  将区间[l; r] 中的每个数修改为x
change l r x 将区间[l; r] 中的每个数加上x
query l r 询问区间[l; r] 中的和

要维护几个东西:
• sum 表示区间的和
• type 表示现在的标记类型(可以是没有标记,可以是增量标记,可以是
赋值标记)
• delta 如果是增量标记,那么这个里面存的增量
• value 如果是赋值标记,那么这里面就存的是那个值
然后就秩序要讨论一下发现:
• 空标记+ 赋值操作= 赋值标记
• 空标记+ 增量操作= 增量标记
• 增量标记+ 赋值操作= 赋值标记
• 增量标记+ 增量操作= 增量标记
• 赋值标记+ 增量操作= 赋值标记
• 赋值标记+ 赋值操作= 赋值标记
因为它们之间能和谐共处(如果A 标记遇见B 操作无法转化为一种现有的标
记,那么他们就不能同时用线段树实现),所以就能完成两种操作同时进行。具
体看代码是怎样合并的。

#include "ctime"
#include "cctype"
#include "cstdio"
#include "cstdlib"

#define rep(i, m, n)  for(register int i = (m); i <= (n); ++i)

template <class T>
inline bool readIn(T& x)  {
    char ch;
    int opt = 1;
    while(!isdigit((ch = getchar())) && ch != '-' && ch != -1);
    if(ch == -1)  return false;
    if(ch == '-')  {
        ch = getchar();
        opt = -1;
    }
    for(x = ch - '0'; isdigit((ch = getchar())); x = (x << 1) + (x << 3) + ch - '0');
    ungetc(ch, stdin);
    x *= opt;
    return true;
}

template <class T>
inline void write(T x)  {
     if (x > 9)
     write(x / 10);
     putchar(x % 10 + 48);
}

template <class T>
inline bool writeIn(T x)  {
     if (x < 0)  {
         putchar('-');
         x = -x;
     }
     write(x);
     return true;
}

typedef long long LL;
const int MAXN = 100005;

struct Node;
void modify( Node *nd, int lf, int rg, int L, int R, LL value );
void change( Node *nd, int lf, int rg, int L, int R, LL delta );

struct Node {
    LL sum;
    int type;
    LL delta, value;
    Node *ls, *rs;
    void update() {
        sum = ls -> sum + rs -> sum;
    }
    void pushdown( int lf, int rg ) {
        if( type == 0 ) return;

        int mid = (lf + rg) >> 1;
        if( type == 1 ) {
            change( ls, lf, mid, lf, mid, delta );
            change( rs, mid+1, rg, mid+1, rg, delta );
            type = 0;
        } else {
            modify( ls, lf, mid, lf, mid, value );
            modify( rs, mid+1, rg, mid+1, rg, value );
            type = 0;
        }
    }
}pool[MAXN << 1], *tail = pool, *root;

int n, m, l, r, x, a[MAXN];

Node *build( int lf, int rg ) {
    Node *nd = ++tail;
    if( lf == rg ) {
        nd -> sum = a[lf];
        nd -> type = 0;
    } else {
        int mid = (lf + rg) >> 1;
        nd -> ls = build( lf, mid );
        nd -> rs = build( mid+1, rg );
        nd -> type = 0;
        nd -> update();
    }
    return nd;
}

void modify( Node *nd, int lf, int rg, int L, int R, LL value ) {
    if( L <= lf && rg <= R ) {
        nd -> sum = (LL)(rg - lf + 1) * value;
        nd -> type = 2;
        nd -> value = value;
        return;
    }
    int mid = (lf + rg) >> 1;
    nd -> pushdown(lf,rg);
    if( L <= mid ) modify( nd -> ls, lf, mid, L, R, value );
    if( R > mid ) modify( nd -> rs, mid+1, rg, L, R, value );
    nd -> update();
}

void change( Node *nd, int lf, int rg, int L, int R, LL delta ) {
    if( L <= lf && rg <= R ) {
        nd -> sum += (LL)(rg - lf + 1) * delta;
        if( nd -> type == 0 ) {
            nd -> type = 1;
            nd -> delta = delta;
        } else if( nd -> type == 1 )
            nd -> delta += delta;
         else if( nd -> type == 2 )
            nd -> value += delta;
        return;
    }
    int mid = (lf + rg) >> 1;
    nd -> pushdown(lf,rg);
    if( L <= mid ) change( nd -> ls, lf, mid, L, R, delta );
    if( R > mid ) change( nd -> rs, mid+1, rg, L, R, delta );
    nd -> update();
}

LL query( Node *nd, int lf, int rg, int L, int R ) {
    if( L <= lf && rg <= R ) 
        return nd -> sum;
    int mid = (lf + rg) >> 1;
    nd -> pushdown(lf, rg);
    LL rt = 0;
    if( L <= mid ) rt += query( nd -> ls, lf, mid, L, R );
    if( R > mid ) rt += query( nd -> rs, mid+1, rg, L, R );
    return rt;
}

int main()  {
    freopen("setmod.in", "r", stdin);
    freopen("setmod.out", "w", stdout);
    readIn(n);readIn(m);
    rep(i, 1, n)  readIn(a[i]);
    root = build(1, n);
    while( m-- )  {
        static char s;
        while((s = (char) getchar()) == ' ' || s == '\n');
            if(s == 'q')  {
                readIn(l), readIn(r);
                writeIn(query(root, 1, n, l, r));
                putchar(10);
            }  else  {
                readIn(l);readIn(r);readIn(x);
                if(s == 'c')  change(root, 1, n, l, r, x);  
                else  modify(root, 1, n, l, r, x);
            }
    }
}

你可能感兴趣的:(线段树)