树状数组
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;
}