【bzoj1078】 SCOI2008—斜堆
http://www.lydsy.com/JudgeOnline/problem.php?id=1078 (题目链接)
题意
给出一个斜堆,并给出其插入的操作,求一个字典序最小的插入顺序。
Solution
YY了很久,画出样例,你会发现很神奇的性质:一般情况下,因为是一个一个插入节点的,左子树与右子树的大小要么相等要么左子树比右子树大1。
然而,我忽略了一条链的情况,写写画画搞来搞去,最后分类讨论了一下。关键的地方是要想到我们对于一棵子树,在前提条件相同的情况下,应尽肯能的早插入根,因为是个小根堆,所以根的字典序一定是最小的。
我们这样操作:对于节点x,它的左儿子l,右儿子r。dfs下去,分别得到l的子树的合并顺序和r的子树的合并顺序,再对x,l,r进行合并,跟归并排序有些类似吧。
对于节点x:
左子树大于右子树
1.左-右>=2
不停插左,直到左右子树大小相等
插根,先插左再插右
2.左-右=1
插根,先插左再插右
左子树等于右子树
插根,先插右再插左
左子树小于右子树
1.右-左>=2
不停插右,直到左-右=1
插根,先插左再插右
2.右-左=1
先插右2个
插根,先插左再插右
然后一路dfs递归合并就可以了
细节
节点标号从1开始会比较好
代码
// bzoj1078 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #define LL long long #define inf 1<<30 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=100; struct heap {int l,r;}tr[maxn]; int size[maxn],n; vector<int> v[maxn]; void dfs(int x) { size[x]=1; if (tr[x].l) dfs(tr[x].l); if (tr[x].r) dfs(tr[x].r); size[x]+=size[tr[x].l]+size[tr[x].r]; } void merge(int x) { int l=tr[x].l,r=tr[x].r; if (l) merge(l); if (r) merge(r); int ll=0,rr=0; if (size[l]>size[r]) { if (size[l]-size[r]>=2) { for (;size[l]-size[r];ll++,size[l]--) v[x].push_back(v[l][ll]); v[x].push_back(x); while (size[l] || size[r]) { if (size[l]==size[r]) v[x].push_back(v[r][rr++]),size[r]--; else v[x].push_back(v[l][ll++]),size[l]--; } } else { v[x].push_back(x); while (size[l] || size[r]) { if (size[l]==size[r]) v[x].push_back(v[r][rr++]),size[r]--; else v[x].push_back(v[l][ll++]),size[l]--; } } } else if (size[l]==size[r]) { v[x].push_back(x); while (size[l] || size[r]) { if (size[l]==size[r]) v[x].push_back(v[r][rr++]),size[r]--; else v[x].push_back(v[l][ll++]),size[l]--; } } else if (size[l]<size[r]) { if (size[r]-size[l]>=2) { for (;size[l]-size[r]<1;rr++,size[r]--) v[x].push_back(v[r][rr]); v[x].push_back(x); while (size[l] || size[r]) { if (size[l]==size[r]) v[x].push_back(v[r][rr++]),size[r]--; else v[x].push_back(v[l][ll++]),size[l]--; } } else { v[x].push_back(v[r][rr++]),size[r]--; v[x].push_back(v[r][rr++]),size[r]--; v[x].push_back(x); while (size[l] || size[r]) { if (size[l]==size[r]) v[x].push_back(v[r][rr++]),size[r]--; else v[x].push_back(v[l][ll++]),size[l]--; } } } } int main() { scanf("%d",&n); for (int x,i=1;i<=n;i++) { scanf("%d",&x); if (x<100) tr[x+1].l=i+1; else tr[x-99].r=i+1; } dfs(1); merge(1); for (int i=0;i<v[1].size();i++) printf("%d ",v[1][i]-1); return 0; }
This passage is made by MashiroSky.