pku 1785 Binary Search Heap Construction(笛卡尔树/Treap)

转个分析:

题目给出的是一棵具有两个关键字的树,于是很自然地往Treap的方向去做了。结果成功的在 #15 TLE了。原因是这样构建Treap,给定的A[]已经不是随机的了,很容易退化成单链,造成O(N^2)的复杂度。

 

由于题目的特殊性(都怪我忽视了题目名称。。。),我们可以直接用构造笛卡尔树的方法来解决这个问题。

 

 

1、 要求的二叉树T的结点K值构成排序二叉树óT的中序遍历的各结点的K值递增。

2、 K值排序后即可得到T的中序遍历{P1,P2,…Pn}

3、 问题转化为:n个结点1~n,每个结点仅有一个权值Bi{Bi=APi},要求建一个堆,并且中序遍历为1~n。排序K值后从最右的路径插入结点,如果结点的A值大于A[i],则旋转,否则直接作为右结点插入。(实际上是Treap的左旋操作)

 

实际的操作很简单:排序->从第二个结点开始插入:链在最右边,递归左旋->由映射恢复原序->输出。

排序的复杂度为O(NlogN),插入结点的复杂度为O(N),因为每个结点最多只是进出一次,所以总的复杂度是O(NlogN)的。要注意的是需要构建结点的映射关系,以便最后按原序输出。

 

#include<stdio.h>
#include<string.h>
#include <algorithm>

 

using namespace std;

 

#define MAXKEY 50
#define MAXNSIZE 50010

 

struct CTNode //Cartesian_Tree node
{
    CTNode() {}
    char key[MAXKEY];
    int priority;
    int parent,l,r;
};
CTNode node[MAXNSIZE];

inline bool mycmp(const CTNode &n1,const CTNode &n2)
{
    return strcmp(n1.key,n2.key)<0;
}

void insert(int x,int inidx)
{
    node[inidx].parent=node[inidx].l=node[inidx].r=-1;
    while(x!=-1)
    {
        if(node[inidx].priority > node[x].priority)
        {
            //左旋
            node[inidx].parent=node[x].parent;
            node[x].r=node[inidx].l;
            node[inidx].l=x;

            x=node[x].parent;
        }
        else
        {
            node[inidx].parent=x;
            node[x].r=inidx;
            return;
        }
    }
}

void display(int root)
{
    printf("(");

    if(node[root].l != -1) display(node[root].l);

    printf("%s/%d",node[root].key,node[root].priority);

    if(node[root].r != -1) display(node[root].r);
    printf(")");
}

int main()
{
    int n,i,p,k;
    while(scanf("%d",&n),n)
    {
        for(k=0; k<n; k++)
        {
            scanf("%s",node[k].key);
            for(i=0; node[k].key[i]!='/'; i++) ;
            node[k].key[i++]=0;
            p=0;
            while(node[k].key[i]) p=p*10+node[k].key[i++]-'0';
            node[k].priority=p;
        }
        sort(node,node+n,mycmp);
        int root=0,last=0;
        node[root].parent=node[root].l=node[root].r=-1;
        for(i=1; i<n; i++)
        {
            insert(last,i);
            if(node[i].parent==-1) root=i;
            last=i;
        }
        display(root);
        printf("\n");
    }
    return 0;
}

 

posted @ 2010-08-23 18:03  菜到不得鸟  阅读(1148)  评论(0)    收藏  举报