[SCOI2008]斜堆

https://zybuluo.com/ysner/note/1222559

题面

斜堆是一种二叉树,且每个非根结点的值都比它父亲大。
在斜堆\(H\)中插入新元素\(X\)的过程是递归进行的:

  • \(H\)为空或者\(X\)小于\(H\)的根结点时,\(X\)变为新的树根,而原来的树根(如果有的话)变为\(X\)儿子。
  • \(X\)大于\(H\)的根结点时,\(H\)根结点的两棵子树交换,而\(X\)(递归)插入到交换后的子树中。

现给出一个大小为\(n+1\)的斜堆,询问该斜堆字典序最小的插入序列。

  • \(n\leq50\)

    解析

    经过审题,我们发现每次插入元素后,该子树的根一定会有左子树,而右子树只能通过新元素经过、结点交换左右子树产生。
    然后就看不出什么了?

一开始,我们不会求插入序列,但我们似乎可以求最后插入的那个元素。

  • 它是极左点(即从根往下走的都是左子树)。
  • 它没有右子树(因为没有新元素经过它往下走)。

于是我们可以初步确定它是极左链上的几个元素,但是并不确定他是哪一个。
对此可以讨论一下。设\(x,y\)为符合条件的两点,\(x\)深度大于\(y\)

  • 如果\(x\)是最后插入的:
    \(deep_x>deep_y\)可知,\(x\)插入时一定经过了\(y\),则\(y\)一定交换过左右子树。而\(y\)又满足最终只有右子树的性质,所以在\(x\)经过前,\(y\)只能有右子树或者没有子树。而这是不可能的。

因而可证明最后插入的点一定是极左链上深度最小的点,或者是该点的是叶结点的左儿子。
而为了保证字典序最小,如果能取后者就取。

而找出最后插入的点并把它删掉后,问题就转化为规模更小的子问题,我们可以在剩下的斜堆中找出最后插入的点,以此类推。
时间复杂度\(O(nlogn)\)。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
int n,d[100],f[100],ls[100],rs[100],ans[100],top,flag,rt=1;
il ll gi()
{
  re ll x=0,t=1;
  re char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
il void dfs(re int u)
{
  if(!rs[u])
    {
      if(ls[u]&&!ls[ls[u]]&&!rs[ls[u]])
    {
      ans[++top]=ls[u],flag=1;
      ls[u]=0;f[ls[u]]=0;
    }
      else
    {
      ans[++top]=u,flag=1;
      if(u==rt) rt=ls[u];
      ls[f[u]]=ls[u];f[ls[u]]=f[u];f[u]=0;
    }
    }
  if(flag) return;
  if(ls[u]) dfs(ls[u]);
  if(flag) {swap(ls[u],rs[u]);return;}
}
int main()
{
  n=gi();
  fp(i,2,n+1)
    {
      d[i]=gi();
      if(d[i]>=100) rs[d[i]-100+1]=i,f[i]=d[i]-100+1;
      else ls[d[i]+1]=i,f[i]=d[i]+1;
    }
  while(top<=n)
    {
      flag=0,dfs(rt);
    }
  fq(i,top,1) printf("%d ",ans[i]-1);puts("");
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/yanshannan/p/9352349.html
今日推荐