树状数组蛮简单的说~
资料参考:百度百科讲的还是蛮清楚的
摘录一些重要的:
- 一般应用于数组求和, 数据更新。
- 树状数组是一个查询和修改复杂度都为log(n)的数据结构
- 比较:树状数组是一个可以很高效的进行区间统计的数据结构。在思想上类似于线段树,比线段树节省空间,编程复杂度比线段树低,但适用范围比线段树小。
比较重要的地方是
- 树状数组一般都是实时更新实时使用
- 下标从一开始
模板: 一维树状数组
const int N = 32005;
int num[N];
int lowbit(int x)
{
return x & (-x);
}
int getsum(int x)
{
int sum = 0;
while(x>0)
{
sum += num[x];
x -= lowbit(x);
}
return sum;
}
void update(int x, int value)
{
while(x<=N)
{
num[x] += value;
x += lowbit(x);
}
}
int main()
{
int n, i, x;
while(~scanf("%d", &n))
{
memset(num, 0, sizeof(num));
for(i=0;i<n;i++)
{
scanf("%d", &x);
x++; //注意, 树状数组的下标必须从一开始!
printf("%d\n", getsum(x)); //实时更新使用
update(x, 1);
}
}
}
二维模板, 和一维差不多
long long num[MAX][MAX] = {0};
int lowbit(int x)
{
return x&(-x);
}
int getsum(int x, int y)
{
int sum = 0, my = y;
for(;x>0;x-=lowbit(x))
{
for(y=my;y>0;y-=lowbit(y))
sum += num[x][y];
}
return sum;
}
void update(int x, int y, long long val, int n)
{
int my = y;
for(;x<=n;x+=lowbit(x))
{
for(y=my;y<=n;y+=lowbit(y))
num[x][y] += val;
}
}
----------------------------------------------------------吾之名为分割线-------------------------------------------------------------------------------------------------------------------------------
还有一个比较蛋疼的问题是数据范围可能很大,大到数组无法容下, 这时候可以尝试下离散化
离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化
例如:
设有4个数:
1234567、123456789、12345678、123456
排序:123456<1234567<12345678<123456789
=> 1 < 2 < 3 < 4
那么这4个数可以表示成:2、4、3、1
使用STL算法离散化:
思路:先排序,再删除重复元素,然后就是索引元素离散化后对应的值。
假定待离散化的序列为a[n],b[n]是序列a[n]的一个副本,则对应以上三步为:
代码:
for(i=0;i<n;i++)
sub_a[i] = a[i];//创建一个原数组的副本, 一般可以在输入时完成
/* 离散化三部曲*/
sort(sub_a,sub_a+n);
int size=unique(sub_a,sub_a+n)-sub_a;//size为离散化后元素个数
for(i=0;i<n;i++)
a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k为b[i]经离散化后对应的值
对于第3步,若离散化后序列为0, 1, 2, ..., size - 1则用lower_bound,从1, 2, 3, ..., size则用upper_bound,其中lower_bound返回第1个不小于b[i]的值的指针,而upper_bound返回第1个大于b[i]的值的指针,当然在这个题中也可以用lower_bound然后再加1得到与upper_bound相同结果,两者都是针对以排好序列。使用STL离散化大大减少了代码量且结构相当清晰。