POJ-2352-Stars題解(樹狀數組 or 線段樹)

Stars

傳送門:Stars

  • 題意
    將星空看做一個平面,在平面上建立直角座標系,這樣在這個平面上的每個星星都有一個座標。天文學家定義了一個星星的水平:一個星星的水平就是,在這個星星正左邊的星星、正下方的星星以及左下方的星星數目之和,就是這個星星的水平。

    輸入:N代表要輸入的星星的個數。接下來的 N 行,每行兩個整數 x 和 y ,代表這個星星的橫縱座標。這裏在輸入時有一個規則,就是按照 y 座標的升序排列, y 座標相等的按照 x 座標的升序排列。

    輸出:每個等級對應的星星數目。

  • 題解
    從題意很容易知道如何計算一個星星的水平,將這個水平的星星數加一,最後輸出即可。問題的關鍵在於如何計算這個星星的水平,如果你仔細觀察一下輸入,你就會發現,星星是按照座標從左到右,從下到上的順序輸入的,因爲星星的水平是計算它正下方、正左方和左下方的星星數,那麼在這個星星之前輸入的星星都是位於這個星星所在的一行或者在它下方,現在要解決的就是如何判斷在它之前輸入的星星裏面,位於它左面的星星,這些星星就是它正下方、正左方和左下方的星星,所以就將問題降到了一維上,現在我們這個二維座標系壓縮到一維,在一維座標系上每個點 x 保存橫座標爲 x 的星星的數量,這時我們需要算這個星星(假設座標爲(a, b))的水平時,只需要計算 0~(a-1)這些點上面的星星的總個數,就是這個星星的水平了。

    接下來就是區間求和的問題了,很容易想到的就是使用樹狀數組線段樹,問題就解決了。下面貼出ac的代碼,包括樹狀數組和線段樹兩個解法。

  • 代碼
    這裏需要注意一下,座標是從 0 開始的,一般在使用樹狀數組或者線段樹的時候,區間是從 1 開始的,所以,需要將橫座標整體加 1 。
    樹狀數組

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define lowbit(x) ((x) & (-x))
    const int MAX = 32005;
    int tree[MAX], ans[MAX];
    int n, x, y;
    void add(int x, int d){
        while(x<=MAX){
            tree[x] += d;
            x += lowbit(x);
        }
    }
    int sum(int x){
        int sum = 0;
        while(x>0){
            sum += tree[x];
            x -= lowbit(x);
        }
        return sum;
    }
    int main(){
        scanf("%d", &n);
        for(int i=0; i<n; i++){
            scanf("%d%d", &x, &y);
            ans[sum(x+1)]++;
            add(x+1, 1);
        }
        for(int i=0; i<n; i++) printf("%d\n", ans[i]);
        return 0;
    }
    

    線段樹

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #define lson l, mid, rt<<1
    #define rson mid+1, r, rt<<1|1
    using namespace std;
    const int MAX = 32e3+5;
    int sum[MAX<<2], ans[MAX];
    int n, x, y;
    
    void push_up(int rt){
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    }
    
    //void build(int l, int r, int rt){
    //    if(l==r){
    //        sum[rt] = 0;
    //        return ;
    //    }
    //    int mid = (l+r)>>1;
    //    build(lson);
    //    build(rson);
    //    push_up(rt);
    //}
    
    int query(int b, int e, int l, int r, int rt){
        if(b<=l && e>=r){
            return sum[rt];
        }
        int mid = (l+r)>>1;
        int ans = 0;
        if(b<=mid) ans += query(b, e, lson);
        if(e>=mid+1) ans += query(b, e, rson);
        return ans;
    }
    
    void update(int x, int l, int r, int rt){
        if(l==r){
            sum[rt]++;
            return ;
        }
        int mid = (l+r)>>1;
        if(x<=mid) update(x, lson);
        else update(x, rson);
        push_up(rt);
    }
    
    int main(){
        scanf("%d", &n);
        for(int i=0; i<n; i++){
            scanf("%d%d", &x, &y);
            ans[query(1, x+1, 1, 32e3+1, 1)]++;
            update(x+1, 1, 32e3+1, 1);
        }
        for(int i=0; i<n; i++) printf("%d\n", ans[i]);
        return 0;
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章