有n頭奶牛,已知它們的身高為 1~n 且各不相同,但不知道每頭奶牛的具體身高。現在這n頭奶牛站成一列,已知第i頭牛前面有ai頭牛比它低,求每頭奶牛的身高。
輸入格式
第1行:輸入整數n。
第2…n行:每行輸入乙個整數ai,第i行表示第i頭牛前面有ai頭牛比它低。
(注意:因為第1頭牛前面沒有牛,所以並沒有將它列出)
輸出格式
輸出包含n行,每行輸出乙個整數表示牛的身高。
第i行輸出第i頭牛的身高。
資料範圍
1≤n≤105
輸入樣例:51
210輸出樣例:24
531先說一下樹狀陣列,樹狀陣列是個很神奇的資料結構,定義tr[x]為區間長度為lowbit(x),末尾時x的區間和,就是[x-lowbit(x)+1,x]的區間和。
lowbit(x)=x&-x;
int
lowbit
(int x)
tr[x]是[x-lowbit(x)+1,x]的和,那麼如果想求[1,n]的和該怎麼求,tr[x-lowbit(x)]是不是剛好與tr[x]無縫相連,那麼一直這項拼接下去直到區間起點為1就可以了(可以證明這樣是一定存在的)
int
sum(
int x)
如果還想修改某個點的值那該怎麼做呢,假設要修改點x位置的值,只需要找一下有那麼些 tr 區間是包含點x的,tr[x]是一定得,然後得繼續向後找,
假設x二進位制為101011:
lowbit(x)=1,x+lowbit=101100,lowbit(x+lowbit)=100,
x+lowbit-lowbit(x+lowbit(x))=101000void
add(
int x,
int d)
//第x個數加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
using
namespace std;
typedef
long
long ll;
const
int n=
100010
;int n,a[n]
,tr[n]
;int
lowbit
(int x)
void
add(
int x,
int d)
intsum
(int x)
intmain()
//l是小於等於ai的最大點
a[i]
=l+1
;add
(l+1,-
1);//不能在第0個位置修改,能求和
}for
(int i=
1;i<=n;i++
) cout<
}
再貼一道一模一樣的題: 謎一樣的牛 樹狀陣列
有n頭奶牛,已知它們的身高為 1 n 且各不相同,但不知道每頭奶牛的具體身高。現在這n頭奶牛站成一列,已知第i頭牛前面有ai頭牛比它低,求每頭奶牛的身高。輸入格式 第1行 輸入整數n。第2 n行 每行輸入乙個整數ai,第i行表示第i頭牛前面有ai頭牛比它低。注意 因為第1頭牛前面沒有牛,所以並沒有將...
244 謎一樣的牛(樹狀陣列)
有n頭奶牛,已知它們的身高為 1 n 且各不相同,但不知道每頭奶牛的具體身高。現在這n頭奶牛站成一列,已知第i頭牛前面有ai 頭牛比它低,求每頭奶牛的身高。輸入格式 第1行 輸入整數n。第2 n行 每行輸入乙個整數ai 第i行表示第i頭牛前面有ai 頭牛比它低。注意 因為第1頭牛前面沒有牛,所以並沒...
樹狀陣列 二分 謎一樣的牛
有n頭奶牛,已知它們的身高為 1 n 且各不相同,但不知道每頭奶牛的具體身高。現在這n頭奶牛站成一列,已知第i頭牛前面有ai頭牛比它低,求每頭奶牛的身高。輸入格式 第1行 輸入整數n。第2 n行 每行輸入乙個整數ai,第i行表示第i頭牛前面有ai頭牛比它低。注意 因為第1頭牛前面沒有牛,所以並沒有將...