树状数组,当要求一个数组某一个区间的和时候或者修改一个数组中的数字之后再求区间和时候。
对于直接用数组来求,简直方便太多了。
利用补码的特性:
int lowbit(int x) { return x&(-x); }
int sum(int x) { int ad=0; while(x>0) { ad+=c[x]; x-=lowbit(x); } return ad; }
void add(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } }接下来介绍几道入门的树状数组的题目:
POJ 2352 Stars:
这题的意思当一个星星的左下方有几个星星,则代表这个星星的等级是多少。
然后输出等级0-N(N-1)的星星个数。
这题由于题目已经说了,是按照纵坐标上升(纵坐标相等,横坐标上升)顺序给的
数据。只要按照星星的横坐标放入树状数组中,因为后面的星星的纵坐标一定大于或者等于
前面的星星。只要查看星星横坐标之前有多少个星星就行了,这就用到树状数组中的求和函数。
POJ 2481Cows:
这道题题的意思给你一群牛,每头牛都有一个S,E。
只要Si<Sj&&Ei>Ej,那么就说明牛i比牛j厉害。
那么只要按照题目的要求将数据S按照升序,E按照降序来排列。
那么只要就S放入树状数组 中,判断前面有多少个牛。
就说明前面的牛多比这个牛强壮。
这个还要考虑数据重复这个问题。
POJ 3067 Japan;
题目的意思,西边有N个城市,东边有M个城市,然后中间有K条高速公路。
然后问你这些高速公路总共重合相交的有几个。
这里有点说明:就是当当西边的城市1分别与东边的城市2,4有高速公路,
而这两条高速公路不算相交。
接下来又要对所给的城市进行一个升序排列、
当一条边有交点,必然是前面有其大的东边城市的坐标值。
树状数组中只要将现在所有城市减去比其小的城市就是要求的相交的城市。
POJ 2299-Ultra-QuickSort
这道题的意思,只能交换相邻的两个数字,问最少的交换次数,可以将其变为递增的数组。
这里就要引进一个概念就是逆序数。
例如例子的
9 1 0 5 4
由于要把它排列为上升序列,上升序列的有序就是 后面的元素比前面的元素大
而对于序列9 1 0 5 4
9后面却有4个比9小的元素,因此9的逆序数为4
1后面只有1个比1小的元素0,因此1的逆序数为1
0后面不存在比他小的元素,因此0的逆序数为0
5后面存在1个比他小的元素4, 因此5的逆序数为1
4是序列的最后元素,逆序数为0
然而4+1+0+1+0=6,正好是交换的次数,可以开一个数组,但是由于该题的测试数据过大。
开不了那么大的上限,所以只能用到了离散化。
离散化简单的来说就是给数据都标上下标。那么就
可以节省下来空间。