謎一樣的牛 樹狀數組

有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

先說一下樹狀數組,樹狀數組是個很神奇的數據結構,定義tr[x]爲區間長度爲lowbit(x),末尾時x的區間和,就是[x-lowbit(x)+1,x]的區間和。
lowbit(x)=x&-x;

int lowbit(int x)
{
    return x&-x;//返回二進制下最後一位1所對應的十進制,假設最後一位1是在第i位,就返回2^i
}

tr[x]是[x-lowbit(x)+1,x]的和,那麼如果想求[1,n]的和該怎麼求,tr[x-lowbit(x)]是不是剛好與tr[x]無縫相連,那麼一直這項拼接下去直到區間起點爲1就可以了(可以證明這樣是一定存在的)

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

如果還想修改某個點的值那該怎麼做呢,假設要修改點x位置的值,只需要找一下有那麼些 tr[] 區間是包含點x的,tr[x]是一定得,然後得繼續向後找,
假設x二進制爲101011:
lowbit(x)=1,x+lowbit=101100,lowbit(x+lowbit)=100,
x+lowbit-lowbit(x+lowbit(x))=101000<x;
可以發現x+lowbit(x)會把x最後邊的連續1都進位,x+lowbit-lowbit(x+lowbit(x))就會一定小於x,所以tr[x+lowbit]一定會包含點x,一直令x+=lowbit(x),tr[x]都修改一下就行了。

void add(int x,int d)//第x個數加d
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=d;
}

所以樹狀數組支持單點修改,區間求和,比線段樹作用單一但比線段樹代碼短

然後再看這道題,每頭牛隻知道它前面都幾頭牛比他低,如果ai=0,那麼i就是前i個的最小值,最後一個0呢就一定是1;ai=j,它就是前i個的第j+1小,如果前i個數已經確定那i就是第j和第j+1中間的數,那如果第j和第j+1之間沒有數了就錯誤了,所以不能先確定前面的數,只能先i確定後面的數,那麼前i個數就會有一個可能的集合,再這個集合裏面找到找第j+1小的數就是第i頭牛的高。
初始化的集合一定是1到n,令每個數都等1,已經確定過得高度就改爲0,所以第j+1小的點就是第一個前綴和等於j+1的點,就可以用樹狀數組啦

#include<iostream>
using namespace std;
typedef long long ll;
const int N=100010;
int n,a[N],tr[N];
int lowbit(int x)
{
    return x&-x;
}
void add(int x,int d)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=d;
}
int sum(int x)
{
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

int main()
{
    cin>>n;
    for(int i=2;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) add(i,1);
    for(int i=n;i;i--)
    {
        int l=0,r=n,mid;
        while(l<r)
        {
            mid=l+r+1>>1;
            if(sum(mid)>a[i]) r=mid-1;
            else l=mid;
        }//l是小於等於ai的最大點
        a[i]=l+1;
        add(l+1,-1);//不能在第0個位置修改,能求和
    }
    for(int i=1;i<=n;i++) cout<<a[i]<<endl;
    return 0;
}

再貼一道一模一樣的題:https://www.acwing.com/problem/content/262/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章