POJ 2352 Stars

新人第一次接觸樹狀數組,上課也沒有好好聽講,這裏把做題的時候的一些經驗稍微總結一下以免以後忘掉:

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章