bzoj1078【SCOI2008】斜堆
題意:
? ? ? 斜堆(skew heap)是一種常用的數(shù)據(jù)結(jié)構(gòu)。它也是二叉樹,且滿足與二叉堆相同的堆性質(zhì):每個非根結(jié)點的值都比它父親大。因此在整棵斜堆中,根的值最小。但斜堆不必是平衡的,每個結(jié)點的左右兒子的大小關(guān)系也沒有任何規(guī)定。在本題中,斜堆中各個元素的值均不相同。 在斜堆H中插入新元素X的過程是遞歸進行的:當(dāng)H為空或者X小于H的根結(jié)點時X變?yōu)樾碌臉涓?#xff0c;而原來的樹根(如果有的話)變?yōu)閄的左兒子。當(dāng)X大于H的根結(jié)點時,H根結(jié)點的兩棵子樹交換,而X(遞歸)插入到交換后的左子樹中。 給出一棵斜堆,包含值為0~n的結(jié)點各一次。求一個結(jié)點序列,使得該斜堆可以通過在空樹中依次插入這些結(jié)點得到。如果答案不惟一,輸出字典序最小的解。輸入保證有解。
輸入:
第一行包含一個整數(shù)n。第二行包含n個整數(shù)d1, d2, ... , dn, di < 100表示i是di的左兒子,di>=100表示i
是di-100的右兒子。顯然0總是根,所以輸入中不含d0。
輸出:
僅一行,包含n+1整數(shù),即字典序最小的插入序列。
Sample0.in
6
100 0 101 102 1 2
Sample0.out
0 1 2 3 4 5 6
?
Sample1.in
12?
0 101 1 2 3 105 6 4 104 102 10 5
Sample1.out
2 4 1 6 10 7 9 5 11 12 8 3 0
?
Sample2.in
12?
100 0 102 101 1 2 3 107 8 7 108 5
Sample2.out
8 11 9 7 0 1 10 5 3 4 2 12 6
?
調(diào)了一天QAQ
orz mato神犇 @http://www.cppblog.com/MatoNo1/archive/2013/03/03/192131.html
性質(zhì)1:若一個節(jié)點沒有左兒子,則該節(jié)點一定沒有右兒子。
?因為右兒子是由左兒子旋轉(zhuǎn)得到的,而在旋轉(zhuǎn)的同時左邊一定被插入節(jié)點了。
性質(zhì)2:最后一次插入一定插到極左節(jié)點(一直往左走),顯然得證。
性質(zhì)3:最后一次插入節(jié)點一定沒有右子樹,因為它在插入時一定是將原來的某棵子樹(可以為空)作為它的左子樹。
所以最后插入的節(jié)點一定是滿足性質(zhì)2,3的深度最小的節(jié)點,刪除該點后將其父親到跟的左右子樹交換。
因為如果不選深度最小的,則在交換的時候一定會交換到?jīng)]有右子樹的點,不滿足性質(zhì)1。
特例:若深度最小的滿足性質(zhì)2,3的節(jié)點有左兒子且其左兒子為葉子節(jié)點,則選其左兒子(字典序最小)
因為刪除其左兒子后該點左右子樹為空,滿足性質(zhì)1
所以就不斷找最后加入的節(jié)點即可,記得考慮在刪除根后的影響(我因為這個WA了一下午),還有-1邊界的判定
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int Mx=310; int n,tot,top,fa[Mx],l[Mx],r[Mx],ans[Mx]; void find(int root) {if(r[root]!=0&&l[root]!=0) find(l[root]);else if(l[root]!=0&&l[l[root]]==0&&r[l[root]]==0&&r[root]==0){ans[++tot]=l[root];l[root]=0;}else if(r[root]==0){ans[++tot]=root;if(l[root]!=0) fa[l[root]]=fa[root];if(fa[root]==-1) top=l[root];else l[fa[root]]=l[root];}if(fa[root]!=-1) swap(l[fa[root]],r[fa[root]]); } int main() {scanf("%d",&n);fa[0]=-1;for(int i=1;i<=n;i++){int d;scanf("%d",&d);if(d<100) fa[i]=d,l[d]=i;else fa[i]=d-100,r[d-100]=i;}while(tot!=n) find(top); cout<<top<<" ";for(int i=tot;i>=1;i--) cout<<ans[i]<<" ";return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/xiaoxubi/p/6243888.html
總結(jié)
以上是生活随笔為你收集整理的bzoj1078【SCOI2008】斜堆的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android系统全貌 (转)
- 下一篇: before与after的一些应用总结