POJ-2182-Lost Cows題解(樹狀數組 or 線段樹)

Lost Cows

題目傳送門

  • 題意
    FJ有n頭牛,編號 1~n ,但是這些牛並沒有按照編號排隊,但是 FJ 知道每頭牛前面有幾頭編號比這頭牛編號小,現在問你每頭牛的編號。

  • 題解
    從最後一頭牛開始,其它牛都已經在隊列裏,假如這頭牛前面有 x 頭牛編號比它小,那麼這頭牛就是編號第 x 小(按編號從小到大排序)的牛的編號加一。知道了這頭牛的編號,就可以把這頭牛從隊列中趕走了,因爲有沒有它都不會影響到前邊的牛。這樣,第 n-1 頭牛就成了最後一頭牛,再重複上面的過程就可以了。

    至於解法,可以用暴力解法,每次數 x+1 次,但是複雜度很高,稍有不慎就會超時,但是思路是正確的,只需要降低算法的複雜度就可以了,因爲是找第 x+1 頭牛的編號,相當於求前綴和,很容易想到的就是樹狀數組線段樹。相比線段樹,樹狀數組的代碼更簡潔,因爲只涉及區間求和,所以推薦使用樹狀數組。

    還有,樹狀數組在求區間和的時候使用二分法可以進一步優化。

  • AC代碼

    樹狀數組

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define lowbit(x) ((x) & (-x))
    const int MAX = 10000;
    int tree[MAX], pre[MAX], ans[MAX];
    int n;
    void add(int x, int d){
        while(x<=n){
            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 findpos(int x){
        int l=1, r=n;
        while(l<r){
            int mid = (l+r)>>1;
            if(sum(mid)<x) l = mid+1;
            else r = mid;
        }
        return l;
    }
    int main(){
        scanf("%d", &n);
        pre[1] = 0;
        for(int i=2; i<=n; i++) scanf("%d", &pre[i]);
        for(int i=1; i<=n; i++) tree[i] = lowbit(i);
        for(int i=n; i>0; i--){
            ans[i] = findpos(pre[i]+1);
            add(ans[i], -1);
        }
        for(int i=1; i<=n; i++) printf("%d\n", ans[i]);
        return 0;
    }
    


    線段樹

    #include<iostream>
    #include<stdio.h>
    #include<cmath>
    using namespace std;
    
    const int MAX = 10000;
    int pre[MAX], tree[4*MAX], ans[MAX];
    
    void BuildTree(int n, int last_left){
        int i;
        for(i=last_left; i<last_left+n; i++){
            tree[i] = 1;
        }
        while(last_left != 1){
            for(i=last_left/2; i<last_left; i++){
                tree[i] = tree[2*i] + tree[2*i+1];
            }
            last_left = last_left/2;
        }
    }
    
    int query(int u, int num, int last_left){
        tree[u]--;
        if(tree[u]==0 && u>=last_left){
            return u;
        }
        if(tree[u<<1]<num) return query((u<<1)+1, num-tree[u<<1], last_left);
        else return query(u<<1, num, last_left);
    }
    
    int main(){
        int n, last_left, i;
        scanf("%d", &n);
        pre[1] = 0;
    
        last_left = 1<<(int(log(n)/log(2))+1);
    
        for(i=2; i<=n; i++) scanf("%d", &pre[i]);
    
        BuildTree(n, last_left);
    
        for(i=n; i>=1; i--) ans[i] = query(1, pre[i]+1, last_left) - last_left + 1;
    
        for(i=1; i<=n; i++) printf("%d\n", ans[i]);
    
        return 0;
    }
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章