#簡單分治#[jzoj 2940] 偷懶的小X

題目

話說3008年的Orz教主節,全民狂歡,傳遞教主聖火,以致萬人空巷,股票飛漲。真乃鑼鼓喧天,鞭炮齊鳴,紅旗招展,人山人海吶。可是小X爲了準備NOIP3008,不得不待在家裏好好Coding。小X希望早點結束當天的任務,加入聖火傳遞隊伍中去。
在這個不亞於狂歡節的日子裏,小X的老師卻“公然違抗”休假法令,佈置小X寫一個小根堆,但是小X不會堆的操作,所以想了一個偷懶的辦法:
  堆是一棵完全二叉樹,每個結點有一個權。小根堆的根的權最小,且根的兩個子樹也是一個堆。可以用一個數組a來記錄一棵完全二叉樹,a[1]爲根結點,若結點a[j]不是根結點,那麼它的父親爲a[j/2](取下整);若結點a[k]不是葉子結點,那麼它的左兒子爲a[2k],它的右兒子爲a[2k+1]。
  他希望一組數據按一定順序依次插入數組中(即第i個數爲a[i]),最後得出來就已經是一個堆,即不需要任何交換操作,若有多種方法,輸出字典序最大的一組,顯得這個數據更亂。


解題思路

對於當前序列,我們肯定是選最小的放在堆頂。
然後分左右子樹(大的分左邊,小的分右邊),顯然可以重複現在的選擇。


代碼

#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[70000],m,b[70000];
void fz(int l,int r,int k){
	b[k]=a[l]; 
	if (l==r) return; 
	int mid=(l+r)>>1; 
	fz(mid+1,r,2*k); 
	fz(l+1,mid,2*k+1); 
}
int main(){
	scanf("%d",&n); 
	for(int i=1;i<=n;i++) scanf("%d",&a[i]); 
	sort(a+1,a+n+1); 
	fz(1,n,1); 
	for(int i=1;i<n;i++) printf("%d ",b[i]); printf("%d\n",b[n]); 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章