題目傳送門
樹狀陣列 + 二分
題目描述:給定\(n\)頭牛,且\(h[i]\)表示第\(i\)頭牛前面有\(h[i]\)頭牛比它低,求每頭牛的身高。
思路:需要從最後一頭牛作為突破口,因為最後一頭牛的\(h[n]\)表示,在前面的牛中,有\(h[n]\)頭牛比它矮,即在所有的牛中,有\(h[n]\)頭牛比他矮,因此最後一牛的高度在所有牛中排第\(h[n] + 1\)小。拿第\(n\)頭牛作為資訊點,去掉第\(n\)頭牛,繼續計算第\(n - 1\)頭牛的高度,再去掉第\(n - 1\)頭牛,依次類推… 當列舉到第\(i\)頭牛時,在剩下的牛中高度中排第\(h[i] + 1\)小的高度,即是第\(i\)頭牛的高度。
方法1、可以使用兩重迴圈列舉,先從後往前列舉每頭牛,當列舉到第\(i\)頭牛時,再從\(1\)列舉到\(n\),找到第\(h[i] + 1\)個沒有使用過的數,再對該數進行標記,繼續列舉下一頭牛,時間複雜度\(o(n^2)\),超時
實現**
#include using namespace std;
//通過了 7/10個資料
// const int n = 1e5 + 10;
int h[n];
int st[n];
int ans[n];
int n;
int main()
}cout << "ans[i]:";
for (int i = 1; i <= n; i++) cout << ans[i] << " ";
cout << "st[i]:";
for (int i = 1; i <= n; i++) cout << st[i] << " ";
cout << endl;
}for (int i = 1; i <= n; i++) cout << ans[i] << endl;
return 0;
}
方法2、樹狀陣列 + 二分,從後往前列舉時,有兩個操作
1、從剩餘的數中找第\(k\)小的數
2、刪除某個數
具體步驟
1、對於每頭牛都初始化為\(1\),\(a[i] = 1\),表示每頭牛都未被使用,樹狀陣列維護的是第\(i\)個高度中\(a[1] + a[2] + .. + a[i]\)的值,其中 \(a[i]\) 只有 \(0\) 和 \(1\) 兩種情況。
2、在剩餘的數中找第 \(k\) 小,即在所有滿足 \(sum(x) = k\) 情況中,通過二分找到最小的 \(x\) ,如圖所示
3、找到了當前牛的高度後刪除該牛的高度,繼續列舉
時間複雜度 \(o(nlogn)\)
實現**
#include using namespace std;
const int n = 100010;
int a[n];
int ans[n];
int n;
// t[i]表示樹狀陣列i結點覆蓋的範圍和
int t[n];
//返回非負整數x在二進位制表示下最低位1及其後面的0構成的數值
int lowbit(int x)
//將序列中第x個數加上k
void add(int x, int k)
//查詢序列前x個數的和
int sum(int x)
int main()
ans[i] = l; //記錄答案
add(l, -1); //找到後,這個數-1,標識為0,方便下次求字首和
}//輸出結果
for (int i = 1; i <= n; i++) cout << ans[i] << endl;
return 0;
}
ACwing 244 謎一樣的牛
時 空限制 1s 64mb 有n頭奶牛,已知它們的身高為 1 n 且各不相同,但不知道每頭奶牛的具體身高。現在這n頭奶牛站成一列,已知第i頭牛前面有aiai頭牛比它低,求每頭奶牛的身高。輸入格式 第1行 輸入整數n。第2.n行 每行輸入乙個整數aiai,第i行表示第i頭牛前面有aiai頭牛比它低。注...
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頭牛前面沒有牛,所以並沒有將...