區間乘法,區間加法,單點詢問。html
寫過線段樹模板2的童鞋應該很清楚了吧QAQc++
因爲*
與Markdown衝突,因此用×代替o(* ̄︶ ̄*)o
spa
咱們把一個數表示爲 a[i] × tg2[b[i]] + tg1[b[i]]。tg2表示乘法標記,tg1表示加法標記。code
對於不完整的塊,直接 a[i] = a[i] × tg2[b[i]] + tg1[b[i]] 將這個塊的全部元素都還原,也就是將該塊的標記下傳。htm
對於完整的塊blog
乘法:( a[i] × tg2[b[i]] + tg1[b[i]] ) × c = a[i] × (tg2[b[i]] × c) + (tg1[b[i]] × c) 也就是說,將tg一、tg2都乘c就能夠了get
加法:( a[i] × tg2[b[i]] + tg1[b[i]] ) + c = a[i] × tg2[b[i]] + (tg1[b[i]] + c) 也就是將tg1加上cit
而後就很清楚了ヾ(o・ω・)ノ入門
#include<bits/stdc++.h> using namespace std; #define MAXN 100005 #define mod(x) (1ll * x) % 10007 int n, d; int a[MAXN], b[MAXN], tg1[500], tg2[500]; inline void Push( int wh ){ for ( int i = ( wh - 1 ) * d + 1; i <= wh * d; ++i ) a[i] = mod( 1ll * a[i] * tg2[wh] + tg1[wh] ); tg1[wh] = 0; tg2[wh] = 1; } void Add( int l, int r, int c ){ if ( b[l] == b[r] ){ Push(b[l]); for ( int i = l; i <= r; ++i ) a[i] = mod( a[i] + c ); return; } Push(b[l]); for ( int i = l; b[i] == b[l]; ++i ) a[i] = mod( a[i] + c ); Push(b[r]); for ( int i = r; b[i] == b[r]; --i ) a[i] = mod( a[i] + c ); for ( int i = b[l] + 1; i <= b[r] - 1; ++i ) tg1[i] = mod( tg1[i] + c ); } void Mul( int l, int r, int c ){ if ( b[l] == b[r] ){ Push(b[l]); for ( int i = l; i <= r; ++i ) a[i] = mod( a[i] * c ); return; } Push(b[l]); for ( int i = l; b[i] == b[l]; ++i ) a[i] = mod( a[i] * c ); Push(b[r]); for ( int i = r; b[i] == b[r]; --i ) a[i] = mod( a[i] * c ); for ( int i = b[l] + 1; i <= b[r] - 1; ++i ) tg1[i] = mod( tg1[i] * c ), tg2[i] = mod( tg2[i] * c ); } int main(){ scanf( "%d", &n ); d = sqrt(n); for ( int i = 1; i <= n; ++i ){ scanf( "%d", &a[i] ); b[i] = ( i - 1 ) / d + 1; } for ( int i = 1; i <= b[n]; ++i ) tg1[i] = 0, tg2[i] = 1; for ( int i = 1; i <= n; ++i ){ int opt, l, r, c; scanf( "%d%d%d%d", &opt, &l, &r, &c ); if ( opt == 0 ) Add( l, r, c ); if ( opt == 1 ) Mul( l, r, c ); if ( opt == 2 ) printf( "%d\n", mod(a[r] * tg2[b[r]] + tg1[b[r]]) ); } return 0; }
有多種操做時能夠藉助代數來分析~(^ω^)模板
數列分塊入門7 <-