树状数组的原理介绍可见刘汝佳《算法竞赛入门经典:训练指南》194页,讲的非常好
简单自己对树状数组的基本理解:我们原先不是把数组看成一排吗,但现在不是了,我们用一个类似二叉树的结构来保存数据,存到c当中去,好好研究刘汝佳所画的图。
下面说明基本应用
对于一个n元素的数组A[n],可执行如下操作:
Add(I, d):让A[i]变成A[i]+d。
Query(L, R):返回A[L]+A[L+1]+…+A[R]。
树状数组只能计算A[1]开始的和,A[0]这个元素是不能用的。
代码模板:
//树状数组只能计算A[1]开始的和,A[0]这个元素是不能用的。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
using namespace std;
typedef long long ll;
const int MAXN=50000+5;//最大元素个数
int n;//元素个数
int c[MAXN];//c[i]==A[i]+A[i-1]+...+A[i-lowbit(i)+1]
//返回i的二进制最右边1的值
int lowbit(int i)
{
return i&(-i);
}
//返回A[1]+...A[i]的和
ll sum(int x){
ll sum = 0;
while(x){
sum += c[x];
x -= lowbit(x);
}
return sum;
}
//令A[i] += val
void add(int x, ll val){
while(x <= n){ //注意这里的n,是树状数组维护的长度
c[x] += val;
x += lowbit(x);
}
}
int main()
{
int n,m;
int cas=1;
while(scanf("%d%d",&n,&m)!=-1)
{
memset(c,0,sizeof(c));
}
return 0;
}
二维树状数组
//一个n*n的矩阵,矩阵里的每一个数要么是0,要么是1。
//有两种操作,C操作是将区间[(x1,y1),(x2,y2)]中所有的数反转(0变1,1变0),Q操作是查询f[x][y]的数值
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define N 1040
#define ll long long
using namespace std;
int n;
int bit[N][N];
int sum(int i,int j) ///查询单点的值
{
int s=0;
while(i>0) {
int jj=j;
while(jj>0) {
s+=bit[i][jj];
jj-=jj&-jj;
}
i-=i&-i;
}
return s;
}
void add(int i,int j,int x) {
while(i<=n) {
int jj=j;
while(jj<=n) {
bit[i][jj]+=x;
jj+=jj&-jj;
}
i+=i&-i;
}
}
int main()
{
int t;
cin>>t;
while(t--) {
int q;
scanf("%d%d ",&n,&q);
memset(bit,0,sizeof bit);
char c;
int x,y,x1,y1;
while(q--) {
scanf("%c",&c);
if(c=='C') {
scanf("%d%d%d%d",&x,&y,&x1,&y1);
add(x,y,1);
add(x,y1+1,-1);
add(x1+1,y,-1);
add(x1+1,y1+1,1);//重叠的部分加上
} else {
scanf("%d%d",&x,&y);
cout<<sum(x,y)<<endl;
printf("%d\n",sum(x,y)%2);
}
getchar();
}
if(t)printf("\n");
}
return 0;
}
经典例题:
HDU 1166 敌兵布阵(模板题)
Lightoj 1112 - Curious Robin Hood (树状数组:单点修改 + 区间查询)
下面三个题要一起看:
UVA1428 Ping pong(树状数组+思维)
北京化工大学2018年10月程序设计竞赛 问题 D: 积木 树状数组(这题解决上一个题的一个问题:数据量大,离散化)
TYVJ1432 楼兰图腾 树状数组逆序对
POJ 2481 Cows (树状数组:区间真子集的个数,有点区间逆序对的意味)
HDU 1394 Minimum Inversion Number (树状数组:求逆序对))
牛客练习赛38 部分题解 D出题人的手环 (数组数组求逆序对,这题更好)
Poj 2352 Stars(树状数组)思维
HDU-4000 Fruit Ninja 树状数组+思维
POJ 2828 Buy Tickets(树状数组:统计1的个数或线段树:查找并更新从左到右第i个1)
POJ2182 Lost Cows 树状数组 二分+思维
树状数组优化DP
HDOJ5542-The Battle of Chibi【树状数组优化dp】(推荐,详细介绍)
CF597C. Subsequences [dp树状数组优化]
hdu3450Counting Sequences DP+树状数组