【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;
}
原文地址:https://www.cnblogs.com/MashiroSky/p/6268071.html