裸线段树,不过不是很好写,需要注意的地方挺多的。
用sum[0],sum[1],sum[2]分别记录一次方和,平方和和立方和,更新的时候推一个增量公式:
一次方:sum[0]+=(r - l + 1)*c;
二次方:
∵(a+b)2=a2+2*a*b+b2;
∴ (xl+c)2 + (xl+1+c)2+……+(xr+c)2=xl2+xl+12+……+xr2+2*c*(xl+xl+1+……+xr)+(r-l+1)*c2;
∴ sum[1] = sum[1]+2*c*sum[0]+(r-l+1)*c2;(注:此处的sum[0]是未更新前的sum[0])
三次方:
∵(a+b)3=a3+2*a2*b+2*a*b2+b3;
∴ (xl+c)3 + (xl+1+c)3+……+(xr+c)3
=xl3+xl+13+……+xr3+2*c*(xl2+xl+12+……+xr2)+2*c*c*(xl+xl+1+……+xr)+(r-l+1)*c3;
∴sum[2] = sum[2]+2*c*sum[1]+2*c*c*sum[0]+(r-l+1)*c3;
(注:此处的sum[0]和sum[1]均是未更新前的sum[0]和sum[1])
然后就是懒惰更新的标记,之前我是用了一个oper标记操作,用了一个val标记操作的值,后来发现不行,因为操作是有先后顺序的,所以在更新的时候,如果需要标记当前节点,必须先把当前节点已有的标记PushDown下去。但是这样的话,每个子树都会遇到这个问题,标记就会一直传递下去,直到叶子节点。这样就失去了懒惰标记的意义。
因此我将标记改成了a*x+c的形式,记录a和c,加操作视为1*x+c,乘操作视为a*x+0,重置操作视为0*x+c。但是我每次更新的时候直接覆盖了之前的标记,显然这样是不行的,直接覆盖的话就丢失了之前的更新信息,但是把信息PushDown下去的话又会出现跟上面一样的问题。
怎么才能做到不丢失之前的信息,又不会把更新无限传递下去呢?
还是把信息记录成a*x+b的形式,更新直接在之前的标记上迭代。乘的话直接累乘到a上,加的话直接累加到b上。但是这样又会出现一个问题:先乘后加和先加后乘是不一样的。
这个就比较好处理了:我们每次优先处理乘操作。
更新加法:ax+b+c c直接累加到加法标记b上即可
更新乘法:c*(ax+b)=c*a*x+c*b c先累乘到乘法标记a上,再乘到加法标记b上
这样所有的问题就都解决了~
还有一点小地方:
1.long long int会超时,也可能是我代码比较挫,反正我用long long超时了
2.用int的话最好一乘一取模,不然很容易溢出
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define UNLABLE 1 //未标记 using namespace std; const int MAXN = 100010; const int MOD = 10007; int N, Q; int sum[3][ MAXN << 2 ]; //sum0、1、2分别代表1、2、3次方 int flag[2][MAXN << 2]; //标记操作类型 flag[0]标记加法,flag[1]标记乘法,reset转变成*0+c void build( int l, int r, int rt ) { flag[0][rt] = 0; flag[1][rt] = 1; sum[0][rt] = sum[1][rt] = sum[2][rt] = 0; if ( l == r ) return; int m = ( l + r ) >> 1; build( lson ); build( rson ); return; } inline void Add( int l, int r, int rt, int x ) { if ( x == 0 ) return; int pre0 = sum[0][rt]%MOD; int pre1 = sum[1][rt]%MOD; sum[0][rt] += ((x%MOD) * (r - l + 1)%MOD)%MOD; sum[0][rt] %= MOD; sum[1][rt] += ((((2*x)%MOD)*pre0)%MOD + (((((r-l+1)%MOD)*x)%MOD)*x )%MOD)%MOD; sum[1][rt] %= MOD; sum[2][rt] += ((((3*x)%MOD)*pre1)%MOD + ( ((((3*x)%MOD)*x)%MOD)*pre0 )%MOD + (((((((r-l+1)%MOD)*x)%MOD)*x)%MOD)*x)%MOD)%MOD; sum[2][rt] %= MOD; return; } inline void Multi( int rt, int x ) { if ( x == 1 ) return; int pre = x; x %= MOD; sum[0][rt] *= x; sum[0][rt] %= MOD; x *= pre; x %= MOD; sum[1][rt] *= x; sum[1][rt] %= MOD; x *= pre; x %= MOD; sum[2][rt] *= x; sum[2][rt] %= MOD; return; } inline void PushUp( int rt ) { int lc = rt << 1; int rc = rt << 1 | 1; for ( int i = 0; i < 3; ++i ) { sum[i][rt] = (sum[i][lc]%MOD + sum[i][rc]%MOD)%MOD; } return; } inline void PushDown( int rt, int l, int r ) { int lc = rt << 1; int rc = rt << 1 | 1; int m = ( l + r ) >> 1; if ( flag[1][rt] != 1 ) { flag[1][lc] *= flag[1][rt], flag[1][lc] %= MOD; flag[1][rc] *= flag[1][rt], flag[1][rc] %= MOD; flag[0][lc] *= flag[1][rt], flag[0][lc] %= MOD; flag[0][rc] *= flag[1][rt], flag[0][rc] %= MOD; Multi(lc, flag[1][rt]), Multi(rc, flag[1][rt]); flag[1][rt] = 1; } if ( flag[0][rt] != 0 ) { flag[0][lc] += flag[0][rt]; flag[0][lc] %= MOD; flag[0][rc] += flag[0][rt]; flag[0][rc] %= MOD; Add( lson, flag[0][rt] ), Add( rson, flag[0][rt] ); flag[0][rt] = 0; } return; } void Update( int L, int R, int op, int v, int l, int r, int rt ) { //printf( "Uppre: [%d, %d]: ", l, r ); //printf( "sum0=%d sum1=%d sum2=%d ", sum[0][rt], sum[1][rt], sum[2][rt] ); //printf( "flag0=%d flag1=%d ", flag[0][rt], flag[1][rt] ); if ( L <= l && r <= R ) { switch(op) { case 1: flag[0][rt] += v; flag[0][rt] %= MOD; Add(l, r, rt, v); break; case 2: flag[0][rt] *= v; flag[0][rt] %= MOD; flag[1][rt] *= v; flag[1][rt] %= MOD; Multi(rt, v); break; case 3: flag[0][rt] = v; flag[1][rt] = 0; Multi(rt, 0); Add(l, r, rt, v); break; } //printf( "Upafter: [%d, %d]: ", l, r ); //printf( "sum0=%d sum1=%d sum2=%d ", sum[0][rt], sum[1][rt], sum[2][rt] ); //printf( "flag0=%d flag1=%d ", flag[0][rt], flag[1][rt] ); return; } PushDown(rt, l, r); int m = ( l + r ) >> 1; if ( L <= m ) Update( L, R, op, v, lson ); if ( R > m ) Update( L, R, op, v, rson ); PushUp( rt ); //printf( "Upafter: [%d, %d]: ", l, r ); //printf( "sum0=%d sum1=%d sum2=%d ", sum[0][rt], sum[1][rt], sum[2][rt] ); //printf( "flag0=%d flag1=%d ", flag[0][rt], flag[1][rt] ); return; } int Query( int L, int R, int p, int l, int r, int rt ) { //printf( "pre: [%d, %d]: ", l, r ); //printf( "sum0=%d sum1=%d sum2=%d ", sum[0][rt], sum[1][rt], sum[2][rt] ); //printf( "flag0=%d flag1=%d ", flag[0][rt], flag[1][rt] ); if ( L <= l && r <= R ) { return sum[p - 1][rt]; } PushDown(rt, l, r); int m = ( l + r ) >> 1; int res = 0; if ( L <= m ) res += Query( L, R, p, lson ); if ( R > m ) res += Query( L, R, p, rson ); res %= MOD; PushUp(rt); //printf( "after: [%d, %d]: ", l, r ); //printf( "sum0=%d sum1=%d sum2=%d ", sum[0][rt], sum[1][rt], sum[2][rt] ); //printf( "flag0=%d flag1=%d ", flag[0][rt], flag[1][rt] ); return res; } int main() { //freopen( "in.txt", "r", stdin ); //freopen( "s.txt", "w", stdout ); while ( scanf( "%d%d", &N, &Q ), N || Q ) { build( 1, N, 1 ); while ( Q-- ) { int op, a, b, c; scanf( "%d%d%d%d", &op, &a, &b, &c ); if ( op == 4 ) printf("%d ", Query( a, b, c, 1, N, 1 ) ); else Update( a, b, op, c, 1, N, 1 ); //puts(""); } } return 0; }