# 树状数组 数据结构详解与模板(可能是最详细的了)

### 树状数组基础

C[i]代表 子树的叶子结点的权值之和 如图可以知道

C[1]=A[1];

C[2]=A[1]+A[2];

C[3]=A[3];

C[4]=A[1]+A[2]+A[3]+A[4];

C[5]=A[5];

C[6]=A[5]+A[6];

C[7]=A[7];

C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];


C[1] = C[0001] = A[1];

C[2] = C[0010] = A[1]+A[2];

C[3] = C[0011] = A[3];

C[4] = C[0100] = A[1]+A[2]+A[3]+A[4];

C[5] = C[0101] = A[5];

C[6] = C[0110] = A[5]+A[6];

C[7] = C[0111] = A[7];

C[8] = C[1000] = A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];


k k i i 的二进制中从最低位到高位连续零的长度）例如 i = 8 ( 1000 ) i=8(1000) 时， k = 3 k=3 ;

C [ 8 ] = A [ 8 − 2 3 + 1 ] + A [ 8 − 2 3 + 2 ] + … … + A [ 8 ] C[8]=A[8−2^3+1]+A[8−2^3+2]+……+A[8] 即为上面列出的式子

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


1(001)

C[1]+=A[1]

lowbit(1)=001 1+lowbit(1)=2(010) C[2]+=A[1]

lowbit(2)=010 2+lowbit(2)=4(100) C[4]+=A[1]

lowbit(4)=100 4+lowbit(4)=8(1000) C[8]+=A[1]


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


i=5

C[4]=A[1]+A[2]+A[3]+A[4];

C[5]=A[5];


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


lowbit 会了,区间查询有了,单点更新也有了接下来该做题了 HDU1166敌兵布阵

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#define For(a,b) for(int a=0;a<b;a++)
#define mem(a,b) memset(a,b,sizeof(a))
#define _mem(a,b) memset(a,0,(b+1)<<2)
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
const int maxn =  5*1e4+5;
const int INF = 0x3f3f3f3f;
int c[maxn];
void update(int x,int y,int n){
for(int i=x;i<=n;i+=lowbit(i))
c[i] += y;
}
int getsum(int x){
int ans = 0;
for(int i=x;i;i-=lowbit(i))
ans += c[i];
return ans;
}
int main()
{
int t;
int n;
int x,y,z;
string s;
cin >> t ;
for(int j=1;j<=t;j++){
scanf("%d",&n);
_mem(c,n);

//初始化数组中前n+1个数为0
for(int i=1;i<=n;i++){
scanf("%d",&z);
update(i,z,n);
}
cout <<"Case "<<j<<":"<<endl;
while(1){
cin >> s;
if(s[0] == 'E')
break;
scanf("%d%d",&x,&y);
if(s[0] == 'Q')
cout << getsum(y)-getsum(x-1)<<endl;
else if(s[0] == 'A')
update(x,y,n);
else
update(x,-y,n);
}
}
return 0;
}


# 高级操作


void update(int p)
{
while(p<=n)
{
a[p] ++;
p+=lowbit(p);
}
}

int getsum(int p)
{
int res = 0;
while(p)
res += a[p],p -= lowbit(p);
return res;
}


a 的逆序对个数为：

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


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


void add(int p, int x){ //这个函数用来在树状数组中直接修改
while(p <= n) sum[p] += x, p += p & -p;
}
void range_add(int l, int r, int x){ //给区间[l, r]加上x
}
int ask(int p){ //单点查询
int res = 0;
while(p) res += sum[p], p -= p & -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){
}
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){
}


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


 1  4  8
6  7  2
3  9  5


 1  3  4
5 -2 -9
-3  5  1


0  0  0  0  0
0 +x  0  0 -x
0  0  0  0  0
0  0  0  0  0
0 -x  0  0 +x


0  0  0  0  0
0  x  x  x  0
0  x  x  x  0
0  x  x  x  0
0  0  0  0  0


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


(d[h][k]为点(h, k)对应的“二维差分”(同上题))

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
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, 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(){
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--){
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('\n');
}
return 0;
}

06-26 71
02-21 1809

07-11 3229
04-20 88
09-21 417
10-03 118
02-13 15
09-10 20
07-16 38
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客