• 树状数组


    树状数组总结

            首先我们来说一下这个算法的正确性,从一维开始吧,我们假设有两个点,i,i1,i一直加上lowbit(i),而i1一直减去lowbit(i1),这是两个严格单调的序列,如果这两个序列有交点,则有且只有一个交点k,则从i~i1这一段的和可以用c[k]来记录(且只有一个c[k]满足)。

            二维树状数组也是类似,首先明确二维的c[i][j]记录的是以( i,j  )为右下,( i-lowbit(i)+1 ,j-lowbit(j)+1   )为左上的矩形中所含元素的和(  至于为什么不能理解为一排一排的一维树状数组,是因为这样时间复杂度会从(logn)^2变为nlogn),假设有一个点(  i1 , j1 ),i 与 i1 可以确定好交点的横坐标, 而 j 与 j1 可以确定该交点宗坐标,则交点确定。

    例题

    Problem                                                 
    给出N M 的一个矩阵,初始时全部元素为0,有两种操作:
    • modify x y d:将位置(x,y) 的值加上d。
    • query x1 y1 x2 y2:询问(x1,y1)-(x2,y2) 这个矩形的和。1
    Input
    第1 行,3 个整数N;M;Q,分别表示矩阵的行数、列数及询问数。
    接下来Q 行,每行是上面两种操作之一。
    Output
    对于每个询问,输出询问结果。
    Sample
    matsum.in matsum.out
    2 2 4
    modify 1 1 4
    query 1 1 2 2
    modify 2 2 -4
    query 1 1 2 2
    40
    Note
    • 对于30% 的数据,1  N;M;Q  500;
    • 对于另外30% 的数据,N = 1; 1  M;Q  105;
    • 对于另外40% 的数据,1  N;M  103; 1  Q  105;
    • 对于所有数据,jdj  100; 1  x  N; 1  y  M; 1  x1  x2  N; 1  y1  y2  M ;

    #include <cstdio>
    
    int n, m, q;
    
    struct Case1 {
        int bit[100010];
        void modify( int p, int d ) {
            for( int i = p; i <= m; i += i & -i )
                bit[i] += d;
        }
        int query( int r ) {
            int rt = 0;
            for( int i = r; i; i -= i & -i ) 
                rt += bit[i];
            return rt;
        }
        int query( int l, int r ) {
            return query(r) - query(l-1);
        }
        void solve() {
            while (q--) {
                char ss[100];
                scanf( "%s", ss );
                if( ss[0] == 'm' ) {
                    int x, y, d;
                    scanf( "%d%d%d", &x, &y, &d );
                    modify( y, d );
                } else {
                    int x1, y1, x2, y2;
                    scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 );
                    printf( "%d
    ", query(y1,y2) );
                }
            }
        }
    }case1;
    struct Case2 {
        int bit[1100][1100];
        void modify( int x, int y, int d ) {
            for( int i = x; i <= n; i += i & -i )
                for( int j = y; j <= m; j += j & -j )
                    bit[i][j] += d;
        }
        int query( int x, int y ) {
            int rt = 0;
            for( int i = x; i; i -= i & -i )
                for( int j = y; j; j -= j & -j )
                    rt += bit[i][j];
            return rt;
        }
        int query( int x1, int y1, int x2, int y2 ) {
            return query(x2,y2) - query(x1-1,y2) - query(x2,y1-1) + query(x1-1,y1-1);
        }
        void solve() {
            while(q--) {
                char ss[100];
                scanf( "%s", ss );
                if( ss[0] == 'm' ) {
                    int x, y, d;
                    scanf( "%d%d%d", &x, &y, &d );
                    modify( x, y, d );
                } else {
                    int x1, y1, x2, y2;
                    scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 );
                    printf( "%d
    ", query(x1,y1,x2,y2) );
                }
            }
        }
    }case2;
    
    int main() {
        freopen ( "matsum.in", "r", stdin ) ;
        freopen ( "matsum.out", "w", stdout ) ;
        scanf( "%d%d%d", &n, &m, &q );
        if( n == 1 )
            case1.solve();
        else
            case2.solve();
    }
  • 相关阅读:
    Pandas对于CSV的简单操作
    前端之BOM和DOM
    前端之JavaScript
    前端之CSS初识
    定时ping取返回值并绘图
    etree不存在解决方法
    内置方法练习(一)
    pip使用
    python变量、变量属性
    python 爬取段子网段子写入文件
  • 原文地址:https://www.cnblogs.com/ganster/p/8419489.html
Copyright © 2020-2023  润新知