新人第一次接觸樹狀數組,上課也沒有好好聽講,這裏把做題的時候的一些經驗稍微總結一下以免以後忘掉:
1、對於一個樹狀數組c[n],其中每個元素的值是對應的原數組a[n - 2^k +1]到a[n]的所有數字的和;
2、其中的k爲數字n的最低的不爲0的位的位置,習慣上將2^k稱爲low_bit,求low_bit的方法爲n&(-n);
3、每一個節點c[i]管轄的範圍的寬度都是2的冪數,low_bit(i)求出來的就是把i用2的次冪數進行分解求和的時候指數最小的那一項,c[i+low_bit]得到的就是c[i]的父節點,c[i]的值是其父節點管轄的值的一部分,因此要更新第i個值的時候,要把c[i]的所有父節點依次更新,以下是簡單的函數實現:
void sum_update(int i,int val){
while(i<=maxn){
c[i]+=val;
i += low_bit(i);
}
}
4、求數組的前i項和的時候,c[i-low_bit(i)]即爲與c[i]管轄區間不重疊的前一個區間的各個數的和,因此只要不斷減這一個值,最終就可以求前n項和,當求某一個區間的和的時候,只需要兩個前n項和相減即可,以下是簡單的代碼實現:
int getsum(int i){
int nSum = 0;
while(i>0){
nSum += c[i];
i -= low_bit(i);
}
return nSum;
}
5、值得注意的一點就是樹狀數組不能有標號爲0的元素,因爲low_bit(0)==0,所以會陷入死循環,在建立樹狀數組的時候可以對全部的元素編號加一,處理的時候要格外小心。
6、言歸正傳,關於stars這道題最巧妙的地方在於利用星星座標的有序性,完全不需要使用y座標,直接用x座標對數組進行多次更新,並且在更新後求和,相當於一個滾動數組吧,有時間還會多做幾道關於樹狀數組的題目。
7、說的不是很清楚,主要是給自己看的防止自己忘掉,請看官多多包涵~
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 32010
#define maxs 15010
int cnt[maxs]={0};
int tree[maxn]={0};
int N;
int lowbit(int n){
return n&(-n);
}
int getsum(int x){
int tsum = 0;
while(x>0){
tsum += tree[x];
x -= lowbit(x);
}
return tsum;
}
void add(int x){
while(x<maxn){
tree[x]++;
x += lowbit(x);
}
return;
}
int main(){
int x,y;
scanf("%d",&N);
for(int i=0;i<N;++i){
scanf("%d%d",&x,&y);
int sum = getsum(x+1);
cnt[sum]++;
add(x+1);
}
for(int i=0;i<N;++i){
printf("%d\n",cnt[i]);
}
//system("pause");
return 0;
}