zoukankan      html  css  js  c++  java
  • 一维二维树状数组模板

    树状数组也可说是二分索引树,是一种高级数据结构,但其实用起来很方便。

    本文参考博客如下:

    http://www.cppblog.com/menjitianya/archive/2015/11/02/212171.html

    https://blog.csdn.net/zars19/article/details/54620021

    https://www.cnblogs.com/RabbitHu/p/BIT.html



     1、单点修改+区间查询

    int c[maxn];
    int lowbit(int x)//获取最低位1 
    {
        return x&(-x);
    }
    void update(int x,int c)//单点更新 
    {
        for(int i=x;i<=n;i+=lowbit(i))
        {
            c[i]+=c;
         } 
    }
    int query(int x)//查询前缀和 c[1...x] 
    {
        int ans=0;
        for(int i=x;i>=0;i-=lowbit(i))
        {
            ans+=c[i];
        }
        return ans;
    }
    int rgquery(int l,int r)//区间查询 
    {
        return query(r)-query(l-1); 
     } 
    View Code

    2、区间修改+单点查询

     1 int c1[maxn];//拆分数列 
     2 void updata(int x,int y) //a[x-n]区间修改 
     3 {
     4     for(int i=x;i<=n;i+=lowbit(i))
     5     {
     6         c1[i]+=y;
     7     }
     8 }
     9 void range_updata(int l,int r,int val)
    10 {
    11     updata(l,val);
    12     updata(r+1,-val);
    13 }
    14 
    15 int query(int x)
    16 {
    17     int ans=0;
    18     for(int i=x;i;i-=lowbit(i))
    19     {
    20         ans+=c1[i];
    21     }
    22     return ans;
    23 }
    View Code

    3、区间修改+区间查询

     1 void add(ll p, ll x){
     2     for(int i = p; i <= n; i += i & -i)
     3         sum1[i] += x, sum2[i] += x * p;
     4 }
     5 void range_add(ll l, ll r, ll x){
     6     add(l, x), add(r + 1, -x);
     7 }
     8 ll ask(ll p){
     9     ll res = 0;
    10     for(int i = p; i; i -= i & -i)
    11         res += (p + 1) * sum1[i] - sum2[i];
    12     return res;
    13 }
    14 ll range_ask(ll l, ll r){
    15     return ask(r) - ask(l - 1);
    16 }

    二维树状数组

    在一维树状数组中,tree[x](树状数组中的那个“数组”)记录的是右端点为x、长度为lowbit(x)的区间的区间和。
    那么在二维树状数组中,可以类似地定义tree[x][y]记录的是右下角为(x, y),高为lowbit(x), 宽为 lowbit(y)的区间的区间和。

    1、单点修改+区间查询

    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;
        }
    }

    2、区间修改+单点查询

    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;
        }
    }

    3、区间修改+区间查询

     1 const int N = 205;
     2 ll n, m, Q;
     3 ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
     4 void add(ll x, ll y, ll z){
     5     for(int X = x; X <= n; X += X & -X)
     6         for(int Y = y; Y <= m; Y += Y & -Y){
     7             t1[X][Y] += z;
     8             t2[X][Y] += z * x;
     9             t3[X][Y] += z * y;
    10             t4[X][Y] += z * x * y;
    11         }
    12 }
    13 void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
    14     add(xa, ya, z);
    15     add(xa, yb + 1, -z);
    16     add(xb + 1, ya, -z);
    17     add(xb + 1, yb + 1, z);
    18 }
    19 ll ask(ll x, ll y){
    20     ll res = 0;
    21     for(int i = x; i; i -= i & -i)
    22         for(int j = y; j; j -= j & -j)
    23             res += (x + 1) * (y + 1) * t1[i][j]
    24                 - (y + 1) * t2[i][j]
    25                 - (x + 1) * t3[i][j]
    26                 + t4[i][j];
    27     return res;
    28 }
    29 ll range_ask(ll xa, ll ya, ll xb, ll yb){
    30     return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
    31 }
  • 相关阅读:
    2018/01/01Java基础学习——如何通过dos系统的javadoc命令生成API文档
    Go语言的big包实现大整数运算
    HDU5100 Chessboard【组合数学】
    HDU5143 NPY and arithmetic progression【暴力】
    UVALive5402 UVA579 Clock Hands【水题】
    UVA11799 Horror Dash【求极值+水题】
    HDU1017 ZOJ1152 A Mathematical Curiosity【暴力】
    UVALive2536 POJ1248 HDU1015 ZOJ1403 Safecracker【密码+暴力】
    POJ1284 Primitive Roots【原根】
    UVA11340 Newspaper【输入流+map】
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12433289.html
Copyright © 2011-2022 走看看