樹狀數組 - 謎一樣的牛

樹狀數組 - 謎一樣的牛

題目:

有n頭奶牛,已知它們的身高爲 1~n 且各不相同,但不知道每頭奶牛的具體身高。

現在這n頭奶牛站成一列,已知第i頭牛前面有Ai頭牛比它低,求每頭奶牛的身高。

輸入格式
第1行:輸入整數n。

第2…n行:每行輸入一個整數Ai,第i行表示第i頭牛前面有Ai頭牛比它低。
(注意:因爲第1頭牛前面沒有牛,所以並沒有將它列出)

輸出格式
輸出包含n行,每行輸出一個整數表示牛的身高。

第i行輸出第i頭牛的身高。

數據範圍
1≤n≤105

輸入樣例:
5
1
2
1
0
輸出樣例:
2
4
5
3
1

題解:

2nnann1nannan+1nnnan+1 n1n1an1+1 k10[1,x]x kkk給定的第2到n頭牛的信息,首先可以確定的就是最後一頭的身高。\\假設第n頭牛的信息是a_n,即前n-1頭牛當中,比第n頭牛高的共有a_n頭,即第n頭牛是第a_n+1高的,\\n頭牛的身高分別是前n大的自然數,第n頭牛的身高就是就是第a_n+1大的自然數。\\\ \\以此類推,第n-1頭牛的身高就是剩下的n-1個自然數當中第a_{n-1}+1大的自然數。\\\ \\可見,我們每次都需要看還剩下多少自然數沒有被選過,在剩下的這些數當中再選擇第k大的。\\因此,可以用樹狀數組來統計剩下的自然數的個數。\\把每個自然數初始化標記爲1,每選擇一個自然數,就將其標記爲0,\\求[1,x]的前綴和即求前x個自然數中剩下的自然數的個數。\\\ \\查找剩下的自然數中第k大的自然數可以二分,找到第一個前綴和等於k的位置,這個下標就是剩下的第k大的自然數。


代碼:

#include <cstdio>

using namespace std;

const int N=1e5+10;

int n,a[N],tr[N],ans[N];

int lowbit(int x)
{
    return x&-x;
}

void add(int x,int c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}

int sum(int x)
{
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++) scanf("%d",&a[i]);
    
    for(int i=1;i<=n;i++) tr[i]=lowbit(i);   // 等價於add(i,1)
    
    for(int i=n;i;i--)
    {
        int k=a[i]+1;   ///第k小的數即身高
        int l=1,r=n;
        while(l<r)
        {
            int mid=l+r>>1;
            if(sum(mid)>=k) r=mid;
            else l=mid+1;
        }
        ans[i]=r;
        add(r,-1);
    }
    
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章