bzoj 1078 //1078:[SCOI2008]斜堆

bzoj 1078 //1078:[SCOI2008]斜堆   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1078

更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

bzoj 1078   2019-10-24

824 kb 72 ms C++/Edit 1246 B

//1078:[SCOI2008]斜堆
//在线测评地址https://www.luogu.org/problem/P2475
//边读题,边按题意画图,更容易加速理解题意.2019-10-1 7:28

样例1执行过程如下。2019-10-1 9:46

输入 #1

6
100 0 101 102 1 2

输出 #1

0 1 2 3 4 5 6

bzoj 1078 //1078:[SCOI2008]斜堆_第1张图片

样例2执行过程如下。2019-10-1 15:09

输入 #2

6
100 0 2 102 4 104

输出 #2

4 6 5 2 0 1 3

bzoj 1078 //1078:[SCOI2008]斜堆_第2张图片

样例3执行过程如下。2019-10-1 15:34

输入 #3

7
0 100 1 102 2 3 5

输出 #3

2 5 0 3 4 6 7 1

bzoj 1078 //1078:[SCOI2008]斜堆_第3张图片

//此文http://www.cppblog.com/MatoNo1/archive/2013/03/03/192131.html思路不错,摘抄如下
/*
一开始想傻了囧……不过很快就发现这其实是个超级大水题……
考虑斜堆中最后插入的那个结点,容易发现:
(1)它一定是一个极左结点(就是从根往它的路上一直都是沿着左链走),因为插入的时候每次都是插入到左子树中;
(2)它一定木有右子树,因为插入的时候每次都是把原来的某棵子树作为新结点的左子树;

满足(1)(2)的结点可能有多个,但紧接着可以发现,这个斜堆中的每个结点如果木有左子结点,那么也木有右子结点(或者说,每个非叶结点都有左子树),而在插入一个结点之前,其所有的祖先都被交换了左右子树,所以,若新结点的祖先中有满足(1)(2)的,且新结点不是叶结点,那么在新结点插入之前,这个满足(1)(2)的祖先必然是只有右子树而木有左子树的,这与上面的那个性质矛盾,所以,可以得出:最后插入的那个结点一定是满足(1)(2)的结点中,深度最小的那个(设为X),除非X的左子结点是叶结点,此时为了满足字典序最小,应该取X的左子结点为最后插入的。找到这个最后插入的结点以后,只需要把它删掉,并把它的所有祖先交换左右子树,就是插入该结点以前的状态了。这样可以找到字典序最小的插入顺序。
*/

//此文http://hzwer.com/5790.html代码写得不错.
//3个样例通过,提交AC.2019-10-2 10:03
#include
#include
#define maxn 55
int fa[maxn],ls[maxn],rs[maxn],n;//fa父 ls左子 rs右子
int ans[maxn],top=0,root=0;//栈
void swap(int *a,int *b){//交换
    int t;
    t=*a,*a=*b,*b=t;
}
void init(){
    int i,x;
    memset(fa,-1,sizeof(fa)),memset(ls,-1,sizeof(ls)),memset(rs,-1,sizeof(rs));
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&x);
        if(x<100)fa[i]=x,ls[x]=i;
        else x-=100,fa[i]=x,rs[x]=i;
    }
}
void solve(){
    int x=root,t,f,s;//自顶向底开始插入
    while(rs[x]!=-1)x=ls[x];//找深度最小,没有右子树的左节点
    t=ls[x];//t是x的左叶子节点,该叶节点可能不存在.
    if(t!=-1&&ls[t]==-1&&rs[t]==-1)x=t;//存在叶节点t
    ans[++top]=x;//记录插入的节点x
    //删除插入的x节点
    if(x==root)root=ls[x],fa[root]=-1;//x若是根节点
    else{
        f=fa[x],s=ls[x],ls[f]=s,fa[s]=f;//建立x节点的父子联系
        while(f!=-1)swap(&ls[f],&rs[f]),f=fa[f];
    }
}
int main(){
    int i;
    init();
    for(i=1;i<=n+1;i++)solve();
    while(top)printf("%d ",ans[top--]);
    return 0;
}

你可能感兴趣的:(跟着大佬学算法)