zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    openstack 介绍
    python实现图片批量剪裁的程序
    iOS开发多线程篇—GCD介绍
    block代码块介绍
    ios中的界面跳转方式
    NSNotificationCenter消息机制的介绍
    ios的手势操作之UIGestureRecognizer浅析
    collectionViewFlow的界面编写
    UITableView的简单应用介绍
    滚动视图创建
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6268071.html
Copyright © 2011-2022 走看看