poj3481 Double Queue(set模拟or splay)

题目链接

题目意思明确。可以用两个set来模拟,一个大的优先,一个小的优先,同时删除、同时加入。

struct item1 {
    int k, p;
    item1() {}
    item1(int k, int p) : k(k), p(p) {}
    bool operator < (const item1& rhs) const {
        return p < rhs.p;
    }
};
struct item2 {
    int k, p;
    item2() {}
    item2(int k, int p) : k(k), p(p) {}
    bool operator < (const item2& rhs) const {
        return p > rhs.p;
    }
};
set<item1> st1;
set<item2> st2;
int main(int argc, const char * argv[])
{    
    int op;
    while(~scanf("%d", &op) && op) {
        if (op == 1) {
            int k,p;
            scanf("%d%d", &k, &p);
            st1.insert(item1(k, p));
            st2.insert(item2(k, p));
        }else if (op == 2) {
            if (st2.empty()) {
                printf("0\n");
                continue;
            }
            item2 temp2 = *st2.begin();
            st2.erase(temp2);
            item1 temp1(temp2.k, temp2.p);
            st1.erase(temp1);
            printf("%d\n", temp2.k);
        }else if (op == 3) {
            if (st1.empty()) {
                printf("0\n");
                continue;
            }
            item1 temp1 = *st1.begin();
            st1.erase(temp1);
            item2 temp2(temp1.k, temp1.p);
            st2.erase(temp2);
            printf("%d\n", temp1.k);
        }
    }
    return 0;
}

也可以算成splay的入门题,只要保持树的中序遍历是有序的就行。
百度的图讲解很多,易懂。

#include <stdio.h>
#define MAXN 100005
struct TreeNode
{
    //键,子树大小,父节点编号,两个儿子节点编号,当前节点的附加信息
    int key, size, fa, son[2], num;
    TreeNode() {}
    TreeNode(int _key, int _size, int _fa, int _num)
    {
        key = _key;size = _size;fa = _fa;
        num = _num;son[0] = son[1] = 0;
    }
}T[MAXN];
struct SplayTree 
{
    int rt, cnt;
    void init(){cnt = 1, rt = 0;}
    void PushUp(int x)
    {
        T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size + 1;
    }
    /*p是旋转方向,旋转后x的深度-1*/
    void Rotate(int x, int p)
    {
        int y = T[x].fa;
        T[y].son[!p] = T[x].son[p];
        T[T[x].son[p]].fa = y;
        T[x].fa = T[y].fa;
        if (T[x].fa)
            T[T[x].fa].son[T[T[x].fa].son[1] == y] = x;
        T[x].son[p] = y;
        T[y].fa = x;
        /*y under x*/
        PushUp(y);
        PushUp(x);
    }
    /*x旋转到to下面*/
    void Spaly(int x, int to)
    {
        while(T[x].fa != to)
        {
            if (T[T[x].fa].fa == to)
            {
                Rotate(x, T[T[x].fa].son[0] == x);
            }
            else
            {
                int y = T[x].fa, z = T[y].fa;
                int p = (T[z].son[0] == y);/*y的旋转方向*/
                if (T[y].son[p] == x) Rotate(x, !p), Rotate(x, p);
                else Rotate(y, p), Rotate(x, p);
            }
        }
        /*to=0,说明x是主根*/
        if (to == 0) rt = x;
    }
    /*按键查找,没找到返回0*/
    int find(int key)
    {
        int x = rt;
        while(x && T[x].key != key)
        {
            x = T[x].son[key > T[x].key];
        }
        if (x) Spaly(x, 0);/*如果找到,就旋转到根节点下面*/
        return x;
    }

    void insert(int key, int num)
    {
        if (!rt)
        {
            T[rt = cnt++] = TreeNode(key, 1, 0, num);
        }
        else
        {
            /*y纪录的是x的父节点的编号*/
            int x = rt, y = 0;
            while(x)
            {
                y = x;
                x = T[x].son[key > T[x].key];
            }
            /*创建新的节点*/
            T[x = cnt++] = TreeNode(key, 1, y, num);
            T[y].son[key > T[y].key] = x;
            Spaly(x, 0);
        }
    }
    void Delete(int key)
    {
        int x = find(key);
        if (!x) return ;
        /*左找最大键*/
        int y = T[x].son[0];
        while(T[y].son[1]) y = T[y].son[1];
        /*右找最小键*/
        int z = T[x].son[1];
        while(T[z].son[0]) z = T[z].son[0];

        if (!y && !z)
        {
            rt = 0;
            return ;
        }
        if (!y)/*x没有左子树*/
        {
            Spaly(z, 0);
            T[z].son[0] = 0;/*x没有左子树,故son[0] = 0*/
            PushUp(z);
            return ;
        }
        if (!z)/*x没有右子树*/
        {
            Spaly(y, 0);
            T[y].son[1] = 0;/*x没有右子树,故son[1] = 0*/
            PushUp(y);
            return ;
        }
        /*左右子树同时有,先把y移到0下面,在把z移到y下面,注意更新顺序*/
        Spaly(y, 0);
        Spaly(z, y);
        T[z].son[0] = 0;
        PushUp(z);
        PushUp(y);
    }
    /*找第p大*/
    int GetPth(int p)
    {
        if (!rt) return 0;
        int x = rt;//, ret = 0;
        while(x)
        {
            /*当前节点+左子树*/
            if (p == T[T[x].son[0]].size + 1)
            {
                break;
            }
            if (p > T[T[x].son[0]].size + 1)
            {
                p-= T[T[x].son[0]].size + 1;
                x = T[x].son[1];
            }else x = T[x].son[0];
        }
        Spaly(x, 0);
        return x;
    }
}solve;
int nCase = 0;
int main()
{
    // freopen("/Users/jamesqi/Desktop/in.txt","r",stdin);
    int p, key, num, x;
    solve.init();
    while(scanf("%d", &p) && p)
    {
        switch(p)
        {
            case 1:
                /*插入键、值*/
                scanf("%d%d", &num, &key);
                solve.insert(key, num);
                break;
            case 2:
                /*最大值*/
                num = T[solve.rt].size;
                x = solve.GetPth(num);
                if (x)
                {
                    printf("%d\n", T[x].num);
                    solve.Delete(T[x].key);
                }
                else
                    printf("0\n");
                break;
            case 3:
                /*最小值*/
                x = solve.GetPth(1);
                if (x)
                {
                    printf("%d\n", T[x].num);
                    solve.Delete(T[x].key);
                }
                else 
                    printf("0\n");
                break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值