POJ-3481 Double Queue,Treap树和set花式水过!

                                                 Double Queue

   本打算学二叉树,单纯的二叉树感觉也就那几种遍历了, 无意中看到了这个题,然后就花了两天时间又去学了学Treap树,真的不好理解,真应该从基础开始的,但我比较倔强,看到这题一定要先做了再说。上午和某公众号交流了一下,初学,不明白为什么要借助随机优先值来修正,而这题本身自带优先值,为什么不能用这个来修正呢,给出的回答是:为了保证平衡,因为键值生成的BST树有很多种形态,需要另外一个key来保证二叉树的形态,而固定的函数在某些特殊情况下可能会不平衡,所以随机值比较靠谱。题目中所给的优先级不能保证树的形态,随机数辅助性的修正树的形态。还是有点不明白,先来个题解以后回过来应该更好理解了吧。

    当然,这题典型用treap树做,但set、map、SBT、splay都可以的。下面给出Treap和set的方法,set这个相比要更简单,但treap有着set不可比拟的优势

  Treap 

struct node
{
    node *ch[2];
    int r,k,p;
    node(int kk,int pp)
    {
        r=rand();
        k=kk,p=pp;
        ch[0]=ch[1]=NULL;
    }
    int cmp(int x)
    {
        if(x==p) return -1;
        return x<p?0:1;
    }
};
int find(node *root,int d)
{
    while(root->ch[d])
    {
        root=root->ch[d];
    }
    printf("%d\n",root->k);
    return root->p;
}
void rotate(node *&root,int d)
{
    node *tmp=root->ch[d^1];
    root->ch[d^1]=tmp->ch[d];
    tmp->ch[d]=root;
    root=tmp;
}
void insert(node *&root,int k,int p)
{
    if(root==NULL) root=new node(k,p);
    else
    {
        int d=p < root->p?0:1;
        insert(root->ch[d],k,p);
        if(root->ch[d]->r > root->r)//破坏了树的形态
            rotate(root,d^1);
    }
}
void remove(node *&root,int v)
{
    int d=root->cmp(v);
    if(d==-1)
    {
        node *tmp=root;
        if(root->ch[1]&&root->ch[0])
        {
            int d2=root->ch[1]->r < root->ch[0]->r?1:0;
            rotate(root,d2);//哪边小就往哪边旋转
            remove(root->ch[d2],v);
        }
        else
        {
            if(root->ch[0]==NULL) root=root->ch[1];
            else root=root->ch[0];
            delete tmp;//记得删除节点;
        }
    }
    else remove(root->ch[d],v);
}
int main()
{
    int n;
    node *root=NULL;
    while(~scanf("%d",&n)&&n)
    {
        if(n==1)
        {
            int k,p;
            scanf("%d%d",&k,&p);
            insert(root,k,p);
        }
        else
        {
            if(root==NULL) printf("0\n");
            else
            {
                int d=(n==2)?1:0;
                int v=find(root,d);
                remove(root,v);
            }
        }
    }
    return 0;
}

 set

struct p
{
    int r,k;
    bool operator <(const p& tmp)const//自定义优先级
    {return r<tmp.r;}
};
set<p>q;
int main()
{
    q.clear();
     int n;
     while(~scanf("%d",&n)&&n)
     {
         if(n==1)
         {
             int k,r;
             scanf("%d%d",&k,&r);
             p tmp=(p){r, k};
             q.insert(tmp);
         }
         else
         {
             if(q.size()==0) printf("0\n");
             else
             {
                 set<p>::iterator it;
                 if(n==2) it=--q.end();
                 else it=q.begin();
                 printf("%d\n",it->k);
                 q.erase(it);
             }
         }
     }
     return 0;
}
  边学边做,越学发现自己不会的越多,但至少自己是在进步,加油!


转载于:https://www.cnblogs.com/nyist-TC-LYQ/p/7208119.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值