シングルポイント更新
ボイド更新(int型 X、int型 Yを、INT N-){ ため(int型 I = Xを、I <= N; Iは+ = lowbit(I)) // Xが更新された位置であり、yは更新数であり、nはアレイ最大値 C [I] + = Y。 }
クエリ間隔(1 - X)
INT getsum(INT X){ int型 ANS = 0 。 用(int型 ; I; I- = I = xをlowbit(I)) 年 + = C [i]は、 返す歳; }
高度な操作
逆に探しています
アレイのため、それは離散Bとして扱われる[]。インターバルクエリ、次の一点を修正
無効更新(int型P) { 一方、(P <= N) { [P] ++ ; P + = lowbit(P)。 } } int型 getsum(int型P) { int型のres = 0 ; しばらく(P) RES + = A [P]、P - = lowbit(P)。 リターンのres; }
の数と逆の順序:
以下のために(int型 i = 1 ; iが++; iが<= N ){ 更新(B [I] + 1 )。 RES + = I-getsum(B [I] + 1 )。 }
RESは、Bを留意すべきで、依頼[i]が0より大きくなければならない、逆の順序の数であります
最大間隔を求めて
空アップデート(int型 I、int型のV) { 一方、(I <= MAXY) { T [I] = MAX(T [i]は、V)。 I + = lowbit(I)。 } }
int型のクエリ(int型I) { int型 ANS = 0 ; しばらく(I) { 年 = MAX(年のT [i])と、 I - = lowbit(I)。 } 返す歳; }
INT lowbit(INT X){ 戻り X& - X。 } 無効追加(int型の P、int型 X){ // この関数は直接ツリーの配列を変更するために使用されて しばらく(P <= N-){ C [P] + =のX。 P + = lowbit(P)。 } } ボイド range_add(int型 L、INT R&LT、INT X){ // 間隔に[L、R]プラスX 追加(L、X)を、 追加(R + 1、 - X)。 } INT(ASK INT P){ // 単一点クエリ INT RES = 0 ; 一方、(P){ A + B [P]。 P - = lowbit(P)。 } リターンのres; }
ボイド追加(LL pを、LLのX){ ため(int型のI = P; iは= N <; I + = I& - i)を SUM1 [I] + = X、SUM2 [I] + = X * P。 } void range_add(ll l, ll r, ll x){ add(l, x), add(r + 1, -x); } ll ask(ll p){ ll res = 0; for(int i = p; i; i -= i & -i) res += (p + 1) * sum1[i] - sum2[i]; return res; } ll range_ask(ll l, ll r){ return ask(r) - ask(l - 1); }
用这个做区间修改区间求和的题,无论是时间上还是空间上都比带lazy标记的线段树要优。
void add(int x, int y, int z){ //将点(x, y)加上z int memo_y = y; while(x <= n){ y = memo_y; while(y <= n) tree[x][y] += z, y += y & -y; x += x & -x; } } void ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和 int res = 0, memo_y = y; while(x){ y = memo_y; while(y) res += tree[x][y], y -= y & -y; x -= x & -x; } }
void add(int x, int y, int z){ int memo_y = y; while(x <= n){ y = memo_y; while(y <= n) tree[x][y] += z, y += y & -y; x += x & -x; } } void range_add(int xa, int ya, int xb, int yb, int z){ add(xa, ya, z); add(xa, yb + 1, -z); add(xb + 1, ya, -z); add(xb + 1, yb + 1, z); } void ask(int x, int y){ int res = 0, memo_y = y; while(x){ y = memo_y; while(y) res += tree[x][y], y -= y & -y; x -= x & -x; } }
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <iostream> using namespace std; typedef long long ll; ll read(){ char c; bool op = 0; while((c = getchar()) < '0' || c > '9') if(c == '-') op = 1; ll res = c - '0'; while((c = getchar()) >= '0' && c <= '9') res = res * 10 + c - '0'; return op ? -res : res; } const int N = 205; ll n, m, Q; ll t1[N][N], t2[N][N], t3[N][N], t4[N][N]; void add(ll x, ll y, ll z){ for(int X = x; X <= n; X += X & -X) for(int Y = y; Y <= m; Y += Y & -Y){ t1[X][Y] += z; t2[X][Y] += z * x; t3[X][Y] += z * y; t4[X][Y] += z * x * y; } } void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形 add(xa, ya, z); add(xa, yb + 1, -z); add(xb + 1, ya, -z); add(xb + 1, yb + 1, z); } ll ask(ll x, ll y){ ll res = 0; for(int i = x; i; i -= i & -i) for(int j = y; j; j -= j & -j) res += (x + 1) * (y + 1) * t1[i][j] - (y + 1) * t2[i][j] - (x + 1) * t3[i][j] + t4[i][j]; return res; } ll range_ask(ll xa, ll ya, ll xb, ll yb){ return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1); } int main(){ n = read(), m = read(), Q = read(); for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ ll z = read(); range_add(i, j, i, j, z); } } while(Q--){ ll ya = read(), xa = read(), yb = read(), xb = read(), z = read(), a = read(); if(range_ask(xa, ya, xb, yb) < z * (xb - xa + 1) * (yb - ya + 1)) range_add(xa, ya, xb, yb, a); } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++) printf("%lld ", range_ask(i, j, i, j)); putchar('\n'); } return 0; }