CodeForces 390E Inna and Large Sweet Matrix(树状数组改段求段)
樹狀數(shù)組僅僅能實(shí)現(xiàn)線段樹區(qū)間改動(dòng)和區(qū)間查詢的功能,能夠取代不須要lazy tag的線段樹。且代碼量和常數(shù)較小
首先定義一個(gè)數(shù)組 int c[N]; 并清空 memset(c, 0, sizeof c);
1、單點(diǎn)改動(dòng) : c[x] += y; 相應(yīng)的函數(shù)是 change(x, y);
2、求前綴和 :??相應(yīng)的函數(shù)是 int sum(x)
兩種操作的復(fù)雜度都是O(logn)
模板例如以下:
int c[N], maxn; inline int Lowbit(int x){return x&(-x);} void change(int i, int x)//i點(diǎn)增量為x { while(i <= maxn) { c[i] += x; i += Lowbit(i); } } int sum(int x){//區(qū)間求和 [1,x] int ans = 0; for(int i = x; i >= 1; i -= Lowbit(i)) ans += c[i]; return ans; }
怎樣運(yùn)用樹狀數(shù)組進(jìn)行區(qū)間操作
先定義兩個(gè)樹狀數(shù)組 X, Y
如今我們須要對(duì)一個(gè)數(shù)組 int a[N]; 進(jìn)行區(qū)間操作:[L, R] += val 即 for i:L to R a[i] += val;?
再定義一個(gè) int size = R-L+1 , 即區(qū)間長度
相應(yīng)的改動(dòng)是?
1、X[L] += val; ? X[R+1] -= val;
2、Y[L] += -1 * val * (L-1); ? Y[R+1] += val * R;
相應(yīng)的查詢是
當(dāng)我們求和??時(shí)在樹狀數(shù)組中操作是 ans = X.sum(k) * k + Y.sum(k)
分類討論一下k分別在 [1,L-1] , [L, R] , [R+1, +]
1、k[1,L-1] ?
顯然 X.sum(k) == 0 且 Y.sum(k) == 0 -> ans = X.sum(k)*k + Y.sum(k) = 0*i+0 = 0 結(jié)果與實(shí)際相符。
2、k[L, R]?
X.sum(k) * k = X[L] * k = val * k, ? Y.sum(k) = Y[L] = ?-1 * val * (L-1)?
ans = val * k - val * (L-1) = val * ( k - (L-1) );?
3、k[R+1,?]
X.sum(k) * k = ( x[L] + x[R] ) * k = 0 * k = 0;
Y.sum(k) = Y[L] + Y[R] = -val * (L-1) + val * R = val * (R-L+1) = val * size
X.sum(k) * k + Y.sum(k) = val * size
證明完成。
下面模版中兩個(gè)樹狀數(shù)組c[0], c[1] 相應(yīng)上述的X, Y
區(qū)間改動(dòng):add(L, R, val)
求 int a[N]的前綴和 get_pre(R)
區(qū)間查詢:get(L,R)
const int N = 4e5 + 100; template<class T> struct Tree{T c[2][N];int maxn;void init(int x){maxn = x+10; memset(c, 0, sizeof c);}inline int lowbit(int x){ return x&-x; }T sum(T *b, int x){T ans = 0;if (x == 0)ans = b[0];while (x)ans += b[x], x -= lowbit(x);return ans;}void change(T *b, int x, T value){if (x == 0)b[x] += value, x++;while (x <= maxn)b[x] += value, x += lowbit(x);}T get_pre(int r){return sum(c[0], r) * r + sum(c[1], r);}void add(int l, int r, T value){//區(qū)間加權(quán)change(c[0], l, value);change(c[0], r + 1, -value);change(c[1], l, value * (-l + 1));change(c[1], r + 1, value * r);}T get(int l, int r){//區(qū)間求和return get_pre(r) - get_pre(l - 1);} }; Tree<ll> tree;
好了,回歸正題,我們來講一下這道題的題意:
題意:給定n*m的二維平面 w個(gè)操作
int mp[n][m] = { 0 };
1、0 (x1,y1) (x2,y2) value
for i : x1 to x2
for j : y1 to y2?
mp[i][j] += value;
2、1 (x1, y1) (x2 y2)
ans1 = 縱坐標(biāo)在 y1,y2間的總數(shù)
ans2 = 橫坐標(biāo)不在x1,x2間的總數(shù)
puts(ans1-ans2);
代碼例如以下:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std;typedef long long ll; const int N = 4e6+10; int n, m, w; template<class T> struct Tree { ll c[2][N]; int maxn; void init(int x){ maxn = x+10; memset(c, 0, sizeof c); } inline int lowbit(int x){ return x&-x; } ll sum(ll *b, int x){ ll ans = 0; if (x == 0)ans = b[0]; while (x)ans += b[x], x -= lowbit(x); return ans; } void change(ll *b, int x, ll value){ if (x == 0)b[x] += value, x++; while (x <= maxn)b[x] += value, x += lowbit(x); } ll get_pre(int r){ return sum(c[0], r) * r + sum(c[1], r); } void add(int l, int r, ll value){ change(c[0], l, value); change(c[0], r + 1, -value); change(c[1], l, value * (-l + 1)); change(c[1], r + 1, value * r); } ll get(int l, int r){ return get_pre(r) - get_pre(l - 1); } };Tree<ll> x, y; int main() {scanf("%d%d%d", &n, &m, &w);x.init(n); y.init(m); int tmp;ll all = 0;while(w--){scanf("%d", &tmp);int x1, x2, y1, y2, v;if(tmp == 0){scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &v);all += v * (x2-x1+1) * (y2-y1+1);x.add(x1, x2, v * (y2 - y1 + 1));y.add(y1, y2, v * (x2 - x1 + 1));}if(tmp == 1){scanf("%d%d%d%d", &x1, &y1, &x2, &y2);printf("%I64d\n", y.get(1, y2) - y.get(1, y1-1) - (all - x.get(1, x2) + x.get(1, x1 - 1))); }}return 0; }
posted on 2017-04-28 11:55 mthoutai 閱讀(...) 評(píng)論(...) 編輯 收藏
轉(zhuǎn)載于:https://www.cnblogs.com/mthoutai/p/6780958.html
總結(jié)
以上是生活随笔為你收集整理的CodeForces 390E Inna and Large Sweet Matrix(树状数组改段求段)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PlSql加入数据库链接
- 下一篇: 22.调用element方法控制dom元