zoukankan      html  css  js  c++  java
  • 树状数组详解与模版

    单点更新

    void update(int x,int y,int n){
        for(int i=x;i<=n;i+=lowbit(i))    //x为更新的位置,y为加的数,n为数组最大值
            c[i] += y;
    }

    区间查询(1 - x)

    int getsum(int x){
        int ans = 0;
        for(int i=x;i;i-=lowbit(i))
            ans += c[i];
        return ans;
    }

    高级操作

    求逆序对

    对于数组a,我们将其离散化处理为b[].区间查询与单点修改代码如下

    int lowbit(int x) {
        return x & (-x);
    }
    
    void update(int p) {
        while (p <= n) {
            c[p] ++;
            p += lowbit(p);
        }
    }
    
    int getsum(int p) {
        int res = 0;
        while(p) {
            res += c[p];
            p -= lowbit(p);
        }
        return res;
    }

    a的逆序对个数为:

    for(int i = 1; i <= n; i++) {
                update(b[i]);
                res += (i - getsum(b[i]));
            }

    poj 2299

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<list>
    #include<math.h>
    #include<vector>
    #include<stack>
    #include<string>
    #include<cstring>
    #include<string.h>
    
    
    using namespace std;
    typedef long long LL;
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    const int MAXN = 5e5 + 10;
    const double eps = 1e-8;
    
    int c[MAXN];
    int n;
    int a[MAXN],b[MAXN];
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    void update(int p) {
        while (p <= n) {
            c[p] ++;
            p += lowbit(p);
        }
    }
    
    int getsum(int p) {
        int res = 0;
        while(p) {
            res += c[p];
            p -= lowbit(p);
        }
        return res;
    }
    int main()
    {
    
        while (~scanf("%d", &n) && n) {
            memset(c,0,sizeof c);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            sort(a + 1, a + 1 + n);
            int cnt = unique(a + 1, a + 1 + n) - a - 1;
            for (int i = 1; i <= n; i++)
                b[i] = lower_bound(a + 1, a + 1 + cnt, b[i]) - a;
    
            LL res = 0;
            for(int i = 1; i <= n; i++) {
                update(b[i]);
                res += (i - getsum(b[i]));
            }
            printf("%lld
    ",res);
        }
    }
    View Code

    res就是逆序对个数,ask,需注意b[i]应该大于0

    求区间最大值

    void Update(int i,int v)
    {
        while(i<=maxY)
        {
            t[i] = max(t[i],v);
            i += lowbit(i);
        }
    }
    int query(int i)
    {
        int ans = 0;
        while(i)
        {
            ans = max(ans,t[i]);
            i -= lowbit(i);
        }
        return ans;
    }

    int lowbit(int x) {
        return x & -x;
    }
    void add(int p,int x) {    //这个函数用来在树状数组中直接修改
        while(p <= n) {
            c[p] += x;
            p += lowbit(p);
        }
    }
    
    void range_add(int l,int r,int x) {  //给区间[l, r]加上x
        add(l,x);
        add(r + 1, -x);
    }
    int ask(int p) {  //单点查询前缀和
        int res = 0;
        while(p) {
            res += c[p];
            p -= lowbit(p);
        }
        return res;
    }

    void add(ll p, ll x){
        for(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;
        }
    }
    int 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;
        }
        return res;
    }

    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);
    }
    int 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;
        }
        return res;
    }

    #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('
    ');
        }
        return 0;
    }
  • 相关阅读:
    leetcode目录
    Windows下tuxedo配置
    实习总结
    n人比赛,可轮空,比赛轮数和场数
    Ubuntu中Eclipse安装与配置
    Lunix中文乱码解决方案
    tuxedo入门
    useradd和adduser的区别
    每个位上都是素数
    TUXEDO错误解决方案
  • 原文地址:https://www.cnblogs.com/smallhester/p/11345721.html
Copyright © 2011-2022 走看看