树状数组和线段数组,两者在复杂度上同级, 但是树状数组的常数明显优于线段树, 其编程复杂度也远小于线段树.
树状数组的作用被线段树完全涵盖, 凡是可以使用树状数组解决的问题, 使用线段树一定可以解决, 但是线段树能够解决的问题树状数组未必能够解决.
树状数组的突出特点是其编程的极端简洁性, 使用lowbit技术可以在很短的几步操作中完成树状数组的核心操作,与之相关的便是其代码效率远高于线段树。
另外,当问题推广到高维情形时高维树状数组有高维线段树所无法企及的常数优势。
HDU 1166 敌兵布阵
树状数组:
#include <iostream>
using namespace std;
#define maxn 1000010
int c[maxn], n;
int a[maxn];
char ch[100];
int lowbit(int x) {
return x & (-x);//结果等价与return x & (x^(x-1));
}
void Add(int x, int add) {
while(x <= n) {
c[x] += add;
x += lowbit(x);
}
}
int sum(int x) {
int s = 0;
while(x > 0) {
s += c[x];
x -= lowbit(x);
}
return s;
}
int main() {
int t, as, bs, i, q = 1;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
memset(c, 0, sizeof(c));
for(i = 1; i <= n ;i++) {
scanf("%d", &a[i]);
Add(i, a[i]);
}
printf("Case %d:\n", q++);
while(scanf("%s" , ch) != EOF) {
if(!strcmp(ch, "End"))
break;
else if(!strcmp(ch, "Query")) {
scanf("%d%d", &as, &bs);
printf("%d\n", sum(bs) - sum(as - 1));
}else if(!strcmp(ch, "Add")) {
scanf("%d%d", &as, &bs);
Add(as, bs);
} else if(!strcmp(ch, "Sub")) {
scanf("%d%d", &as, &bs);
Add(as, -bs);
}
}
}
}
线段树
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN=50003; int v[MAXN],sum; typedef struct { int left,right,mid; int count; }line; line l[4*MAXN]; void Creat(int a,int b,int r) { if(a==b) { l[r].left=l[r].right=a; l[r].count=v[a]; return; } l[r].left=a; l[r].right=b; l[r].mid=(a+b)/2; Creat(a,l[r].mid,2*r); Creat(l[r].mid+1,b,2*r+1); l[r].count=l[2*r].count+l[2*r+1].count; } void Add(int n,int m,int r) { if(l[r].left==n&&l[r].right==n) { l[r].count+=m; return; } if(n>l[r].mid) { Add(n,m,2*r+1); } else { Add(n,m,2*r); } l[r].count=l[2*r].count+l[2*r+1].count; } void Query(int a,int b,int r) { if(l[r].left==a&&l[r].right==b) { sum+=l[r].count; } else if(a>l[r].mid) { Query(a,b,2*r+1); } else if(b<=l[r].mid) { Query(a,b,2*r); } else { Query(a,l[r].mid,2*r); Query(l[r].mid+1,b,2*r+1); } } int main() { int cnt=1; int t; scanf("%d",&t); while(t--) { printf("Case %d:\n",cnt++); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&v[i]); } Creat(1,n,1); char s[7]; while(scanf("%s",s),s[0]!='E') { int b,c; scanf("%d %d",&b,&c); if(s[0]=='Q') { sum=0; Query(b,c,1); printf("%d\n",sum); } else if(s[0]=='A') { Add(b,c,1); } else if(s[0]=='S') { Add(b,-1*c,1); } } } return 0; }