给你一个序列: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);
}
}
}