zoukankan      html  css  js  c++  java
  • 树状数组 / 二维树状数组

    一维树状数组

    · 单点修改 + 单点查询:

      直接使用即可

    · 区间修改 + 单点查询:

      另外维护一个维护前缀和的树状数组,查询时查询与原值相加即可。

    · 区间修改 + 区间查询:

      若要查询区间$[1, R]$的区间和,可推公式,其中$D[i]$表示差分数组:

    $sumlimits_{i=1}^R sumlimits_{j=1}^i D[j]$
     
    $= sumlimits_{i=1}^R (R - i + 1) * D[i]$
     
    $= (x + 1) sumlimits_{i=1}^R D[i] -  sumlimits_{i=1}^R (i * D[i])$

       此时维护$sum D[i]$及$sum (i * D[i])$就好了。

    二维树状数组

    · 单点修改 + 单点查询:

      二维树状数组就是在一维的基础上维护一个矩阵,直接维护即可。

    · 区间修改 + 单点查询:

      由$Sum[i][j] = Sum[i - 1][j] + Sum[i][j - 1] - Sum[i - 1][j - 1] + a[i][j]$得到启发,可以维护形似$a[i][j] -> a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]$的差分数组,加如下代码即可:

    void Add_Main (int x1, int y1, int x2, int y2, int delta) {
        Add (x1, y1, delta);
        Add (x2 + 1, y1, - delta);
        Add (x1, y2 + 1, - delta);
        Add (x2 + 1, y2 + 1, delta);
    }

    · 区间修改 + 区间查询:

      推公式,可以由每个二元组$(x, y)$的出现次数得:

    $sumlimits_{x=1}^nsumlimits_{y=1}^msumlimits_{i=1}^xsumlimits_{j=1}^yD[i][j]$
     
     
    $= sumlimits_{x=1}^nsumlimits_{y=1}^m D[x][y] (n - x + 1) (m - y + 1)$
     
     
    $= sumlimits_{x=1}^nsumlimits_{y=1}^m (D[x][y] (n + 1) (m + 1) - D[x][y] (n + 1) * y - D[x][y] (m + 1) * x + D[x][y] * x * y)$

      同一维树状数组的区间修改 + 区间查询,维护四个二维树状数组即可。

    · 完整代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 using namespace std;
      6 
      7 typedef long long LL;
      8 
      9 const int MAXN = 2048 + 10;
     10 
     11 int N, M;
     12 
     13 char opt[5];
     14 
     15 int lowbit (int x) {
     16     return x & (- x);
     17 }
     18 
     19 int Tree1[MAXN][MAXN]= {0};
     20 int Tree2[MAXN][MAXN]= {0};
     21 int Tree3[MAXN][MAXN]= {0};
     22 int Tree4[MAXN][MAXN]= {0};
     23 
     24 void Add (int x, int y, int delta) {
     25     int tx = x, ty = y;
     26     while (x <= N) {
     27         y = ty;
     28         while (y <= M) {
     29             Tree1[x][y] += delta;
     30             Tree2[x][y] += ty * delta;
     31             Tree3[x][y] += tx * delta;
     32             Tree4[x][y] += tx * ty * delta;
     33             y += lowbit (y);
     34         }
     35         x += lowbit (x);
     36     }
     37 }
     38 
     39 void Add_Main (int x1, int y1, int x2, int y2, int delta) {
     40     Add (x1, y1, delta);
     41     Add (x2 + 1, y1, - delta);
     42     Add (x1, y2 + 1, - delta);
     43     Add (x2 + 1, y2 + 1, delta);
     44 }
     45 
     46 int Query (int x, int y) {
     47     int tx = x, ty = y;
     48     int cnt = 0;
     49     while (x >= 1) {
     50         y = ty;
     51         while (y >= 1) {
     52             cnt += (tx + 1) * (ty + 1) * Tree1[x][y];
     53             cnt -= (tx + 1) * Tree2[x][y];
     54             cnt -= (ty + 1) * Tree3[x][y];
     55             cnt += Tree4[x][y];
     56             y -= lowbit (y);
     57         }
     58         x -= lowbit (x);
     59     }
     60 
     61     return cnt;
     62 }
     63 
     64 int Query_Main (int x1, int y1, int x2, int y2) {
     65     return Query (x2, y2) - Query (x2, y1 - 1) - Query (x1 - 1, y2) + Query (x1 - 1, y1 - 1);
     66 }
     67 
     68 int getnum () {
     69     int num = 0;
     70     char ch = getchar ();
     71     int flag = 0;
     72 
     73     while (! isdigit (ch)) {
     74         if (ch == '-')
     75             flag = 1;
     76         ch = getchar ();
     77     }
     78     while (isdigit (ch))
     79         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
     80 
     81     return flag ? - num : num;
     82 }
     83 
     84 int main () {
     85     scanf ("%s", opt + 1);
     86     N = getnum (), M = getnum ();
     87 
     88     while (~ scanf ("%s", opt + 1)) {
     89         if (opt[1] == 'L') {
     90             int x1, y1, x2, y2;
     91             int delta;
     92             x1 = getnum (), y1 = getnum (), x2 = getnum (), y2 = getnum ();
     93             delta = getnum ();
     94 
     95             Add_Main (x1, y1, x2, y2, delta);
     96         }
     97         else {
     98             int x1, y1, x2, y2;
     99             x1 = getnum (), y1 = getnum (), x2 = getnum (), y2 = getnum ();
    100 
    101             int ans = Query_Main (x1, y1, x2, y2);
    102             printf ("%d
    ", ans);
    103         }
    104     }
    105 
    106     return 0;
    107 }
    108 
    109 /*
    110 X 4 4
    111 L 1 1 3 3 2
    112 L 2 2 4 4 1
    113 k 2 2 3 3
    114 */
    二维树状数组(区间修改 + 区间查询)
  • 相关阅读:
    对比git rm和rm的使用区别
    Gerrit日常维护记录
    [原创]Gerrit中文乱码问题解决方案分享
    MySQL 高可用架构
    MySQL 高可用架构
    Android L开发指南
    如何使用GOOGLE高级搜索技巧
    Linux定时关机
    Android源码批量下载及导入到Eclipse
    怎样将Android SDK源码 导入到Eclipse中?
  • 原文地址:https://www.cnblogs.com/Colythme/p/9853159.html
Copyright © 2011-2022 走看看