POJ 1442 Black Box

上了半个学期的课以后才发现,原来从来没有认真听过的数算实习才是幕后的大BOSS…每次作业的题目都虐到爆,每节课讲的数据结构都是数算课程上面简单数据结构的升级版,第一次靠自己的能力强行AC了Treap,把自己都感动了。

简单总结一下树堆的性质:

1、树堆,顾名思义就是树和堆的结合体,每个结点除了value值以外还增加了一个priority的值,是每个结点的权值,以最大堆为例,权值最大的点始终在堆的顶部,同时又满足搜索二叉树的性质。

2、在插入一个新的节点的时候,先按照搜索二叉树的性质把插入到叶子节点的位置,然后再使用堆的性质把这个节点siftup到对应的位置,这个时候的问题就在于siftup的时候不能单纯的进行交换,而是采用一种叫做旋转的操作,如图所示:
这里写图片描述
这里以右旋为例,如果X的权值比Y的权值大,就把X和Y的位置互换,然后理所应当地把B接在Y的左孩子结点上(因为B的值比X大比Y小),我在这道题目中的代码实现比较繁琐,不知道有没有更好的方案,我觉得直接模拟实现就好,也需要什么优化。

3、每个结点的权值一般是直接用随机数生成的,这样也导致我每次提交所用的时间都是不一样的= -

4、当我完成树堆的构造之后,输出第i大的数的时候采用的是中序遍历的方法,结果依然TLE(特别想掀桌子),在室友的启发之下,采用了另一种找第k大的数的方法:给每个结点增加一个变量,记录以这个节点为根节点的子树的节点个数,在寻找第k大的数的时候相当于一个在二叉树里面检索某个值的方式来实现,在debug一个多小时之后顺利AC…

#include<iostream>
#include<limits.h>
#include<memory.h>
#include<stdlib.h>
#include<cstdio>
using namespace std;

#define MAXM 30050

struct node{
    int value;
    int size;
    int priority;
    int fa,lc,rc;
};

bool operator < (node a, node b){
    return a.value < b.value;
}

int M,N;
int real_i = 0;
node treap[MAXM];
int copy_i = 0;

void Find2(int root,int k){
    if(!root)
        return;
    if(treap[treap[root].lc].size +1 == k){
        printf("%d\n",treap[root].value);
        return;
    }
    if(treap[treap[root].lc].size >= k){
        Find2(treap[root].lc,k);
    }
    else{
        Find2(treap[root].rc,k-treap[treap[root].lc].size-1);
    }
}

void insert(int _i,int root){
    treap[root].size++;
    treap[0].size = 0;
    if(treap[_i].value > treap[root].value){
        if(treap[root].rc){
            insert(_i,treap[root].rc);
        }
        else{
            treap[root].rc = _i;
            treap[_i].fa = root;
        }
    }
    else{
        if(treap[root].lc){
            insert(_i,treap[root].lc);
        }
        else{
            treap[root].lc = _i;
            treap[_i].fa = root;
        }
    }
}

void Rrot(int i,int j){
    int k = treap[j].fa;
    treap[i].fa = treap[j].fa;

    if(treap[k].lc == j)
        treap[k].lc = i;
    else if(treap[k].rc == j)
        treap[k].rc = i;

    treap[j].lc = treap[i].rc;
    treap[treap[j].lc].fa = j;
    treap[i].rc = j;
    treap[j].fa = i;
    treap[j].size = treap[treap[j].lc].size + treap[treap[j].rc].size + 1;
    treap[i].size = treap[treap[i].lc].size + treap[treap[i].rc].size + 1;
}

void Lrot(int i,int j){
    int k = treap[j].fa;
    treap[i].fa = treap[j].fa;

    if(treap[k].lc == j)
        treap[k].lc = i;
    else if(treap[k].rc == j)
        treap[k].rc = i;

    treap[j].rc = treap[i].lc;
    treap[treap[j].rc].fa = j;
    treap[i].lc = j;
    treap[j].fa = i;
    treap[j].size = treap[treap[j].lc].size + treap[treap[j].rc].size + 1;
    treap[i].size = treap[treap[i].lc].size + treap[treap[i].rc].size + 1;
}

void siftup(int i){
    if(!i)
        return;
    int j = treap[i].fa;
    if(treap[i].priority > treap[j].priority){
        if(treap[j].lc == i){
            Rrot(i,j);
            siftup(i);
        }
        else if(treap[j].rc == i){
            Lrot(i,j);
            siftup(i);
        }
    }
    return;
}

int main(){
    memset(treap,0,sizeof(treap));
    scanf("%d%d",&M,&N);
    treap[0].priority = INT_MAX;
    treap[0].value = INT_MIN;
    treap[0].size = 0;
    for(int i=1;i<=M;++i){
        scanf("%d",&treap[i].value);
        treap[i].priority = rand();
    }
    int mark;

    int i = 1;
    while(N--){
        scanf("%d",&mark);
        for(;i<=mark;++i){
            treap[i].size = 1;
            insert(i,treap[0].rc);
            siftup(i);
        }

        real_i++;
        Find2(treap[0].rc,real_i);
    }
    //system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值