树状数组,个人理解,随时更新

树状数组

1.基本函数

1.lowbit()函数

int lowbit(int x) {
    return x & -x;
}

lowbit()函数就是找到二进制中最后一位1的位置所代表的数,比如lowbit(6)结果为2,lowbit(8)结果为8,lowbit(16)结果为16,而找到里最后一位1的数字那么,操作一下就可以得到下一位或者上一位最近的0的个数比x多的数

比如x=14 lowbit(14) = 2   x二进制为1110 , 加上10 ,那么x + lowbit(x) = 16 ,10000,0的个数比14多,而14-lowbit(14) = 12,二进制为1100,是距离它最近的0的个数比它多的数

2.updata()函数

void updata(int x, int v) {
    while(x <= maxn) {
        c[x] += v;
        x += x & -x;
    }
}

updata()函数就是把它以后的父节点全部更新

3.getsum()函数

int getsum(int x) {
    int res = 0;
    while(x > 0) {
        res += c[x];
        x -= x & -x;
    }
    return res;
}

就是把c[]想做的事情做到,比如c[]想求前n项的和,就算它把每一个数据都更新一遍,c[]代表的也不是前n项的和,而getsum()函数可以得到前n项和,所以用getsum()函数前要想好c[]函数要干什么

以上就是一些基本的函数,可以进行一些基本操作,比如区间修改,单点查询

#include<iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 1e5 + 5;
int c[maxn], sum[maxn], a[maxn];
int lowbit(int x) {
    return x & -x;
}
void updata(int x, int v) {
    while(x <= maxn) {
        c[x] += v;
        x += x & -x;
    }
}
int getsum(int x) {//getsum得到的是a[]的变化量
    int res = 0;
    while(x > 0) {
        res += c[x];
        x -= x & -x;
    }
    return res;
}
void range_updata(int l, int r, int v) {
    updata(l, v);
    updata(r + 1, -v);
}
int main(int argc, const char * argv[]) {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%d", &a[i]);
    }
    int m;
    scanf("%d", &m);
    while(m--) {
        int l, r, v;
        scanf("%d%d%d", &l, &r, &v);
        range_updata(l, r, v);
    }
    for (int i = 1; i <= n; i ++)
        printf("%d ", getsum(i) + a[i]);
    return 0;
}

区间修改,区间查询,可以把区间的每个数相加,但很low,也很耗时间


#include<iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
const int maxn = 1e5 + 5;
int c[maxn], sum1[maxn], a[maxn], sum2[maxn];
int lowbit(int x) {
    return x & -x;
}
void updata(int x, int v) {
    int t = x;
    while(x <= maxn) {
        sum1[x] += v;
        sum2[x] += v * t;
        x += x & -x;
    }
}
int getsum(int x) {
    int res = 0;
    int t = x;
    while(x > 0) {
        res += sum1[x] * (t + 1) - sum2[x];
        x -= x & -x;
    }
    return res;
}
void range_updata(int l, int r, int v) {
    updata(l, v);
    updata(r + 1, -v);
}
int range_getsum(int l, int r) {
    return getsum(r) - getsum(l - 1);
}
int main(int argc, const char * argv[]) {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%d", &a[i]);
    }
    int m;
    scanf("%d", &m);
    while(m--) {
        int l, r, v;
        scanf("%d%d%d", &l, &r, &v);
        range_updata(l, r, v);
        printf("%d\n", range_getsum(l, r));
        //输出的是改变的值
    }
    return 0;
}

二维树状数组

1.单点修改,区间查询

二维数组的根本与一维的类似

void updata(int x, int y, int v) {
    while (x <= maxn) {
        int my= y;
        while(my <= maxn) {
            c[x][my] += v;
            my += my & -my;
        }
        x += x & -x;
    }
}
int getsum(int x, int y) {
    int res = 0;
    while(x > 0) {
        int my = y;
        while(y > 0) {
            res +=c[x][my];
            my -= my & -my;
        }
        x -= x  & -x;
    }
    return res;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81196301