双重队列问题

一 问题描述

银行的每个客户都有一个正整数标识 K,到银行请求服务时将收到一个正整数的优先级 P 。银行经理提议打破传统,在某些时候调用优先级最低的客户,而不是优先级最高的客户。系统将收到以下类型的请求:

① 0,系统需要停止服务。

② 1 K P,将客户 K 及优先级 P 添加到等待列表中。

③ 2,为优先级最高的客户提供服务,并将其从等待名单中删除。

④ 3,为优先级最低的客户提供服务,并将其从等待名单中删除。

二 输入

输入的每一行都包含一个请求,只有最后一行包含停止请求(代码0)。假设有请求在列表中包含新客户(代码1),在同一客户的列表中没有其他请求或有相同的优先级,标识符 K 总是小于10^6 ,优先级 P 总是小于10^7 。一个客户可以多次到银行请求服务,但是每次都获得不同的优先级。

三 输出

对代码为 2 或 3 的每个请求都单行输出所服务客户的标识。若请求在等待列表为空时到达,则输出 0。

四 输入和输出样例

1 输入样例

2

1 20 14

1 30 3

2

1 10 99

3

2

2

0

2 输出样例

0

20

30

10

0

五 分析和设计

本问题包括插入、删除优先级最高元素和删除优先级最低元素等 3 种操作,可以采用 Treap 解决。

六 代码

package com.platform.modules.alg.alglib.poj3481;

import java.util.Random;

public class Poj3481A {
    public String output = "";

    private int maxn = 100005;
    int n; // 结点数
    int cnt; // 结点存储下标累计
    int root; // 树根
    int maxval;
    int minval;
    private node tr[] = new node[maxn];

    public Poj3481A() {
        for (int i = 0; i < tr.length; i++) {
            tr[i] = new node();
        }
    }

    // 生成新结点
    int New(int val, int num) {
        tr[++cnt].val = val;
        tr[cnt].pri = Math.abs(new Random().nextInt()) % 100;
        tr[cnt].num = num;
        tr[cnt].rc = tr[cnt].lc = 0;
        return cnt;
    }

    // 右旋
    int zig(int p) {
        int q = tr[p].lc;
        tr[p].lc = tr[q].rc;
        tr[q].rc = p;
        // 现在 q 为根
        p = q;
        return p;
    }

    // 左旋
    int zag(int p) {
        int q = tr[p].rc;
        tr[p].rc = tr[q].lc;
        tr[q].lc = p;
        // 现在 q 为根
        p = q;
        return p;
    }

    // 在 p 的子树插入值 val
    int Insert(int p, int val, int num) {
        if (p == 0) {
            p = New(val, num);
            return p;
        }
        if (val <= tr[p].val) {
            tr[p].lc = Insert(tr[p].lc, val, num);
            if (tr[p].pri < tr[tr[p].lc].pri)
                p = zig(p);
        } else {
            tr[p].rc = Insert(tr[p].rc, val, num);
            if (tr[p].pri < tr[tr[p].rc].pri)
                p = zag(p);
        }
        return p;
    }

    // 在 p 的子树删除值val
    int Delete(int p, int val) {
        if (p == 0)
            return p;
        if (val == tr[p].val) {
            if (tr[p].lc == 0 || tr[p].rc == 0)
                p = tr[p].lc + tr[p].rc; // 有一个儿子为空,直接用儿子代替
            else if (tr[tr[p].lc].pri > tr[tr[p].rc].pri) {
                p = zig(p);
                tr[p].rc = Delete(tr[p].rc, val);
            } else {
                p = zag(p);
                tr[p].lc = Delete(tr[p].lc, val);
            }
            return p;
        }
        if (val < tr[p].val)
            tr[p].lc = Delete(tr[p].lc, val);
        else
            tr[p].rc = Delete(tr[p].rc, val);
        return p;
    }

    // 找优先级最大的结点编号
    void printmax(int p) {
        while (tr[p].rc > 0) {
            p = tr[p].rc;
        }
        output += tr[p].num + "\n";
        maxval = tr[p].val;
    }

    // 找优先级最低的结点编号
    void printmin(int p) {
        while (tr[p].lc > 0) {
            p = tr[p].lc;
        }
        output += tr[p].num + "\n";
        minval = tr[p].val;
    }

    public String cal(String input) {
        int num, val;
        String[] line = input.split("\n");
        int count = 0;
        while (true) {
            String commad[] = line[count++].split(" ");
            n = Integer.parseInt(commad[0]);
            switch (n) {
                case 0:
                    return output;
                case 1:
                    num = Integer.parseInt(commad[1]);
                    val = Integer.parseInt(commad[2]);
                    root = Insert(root, val, num);
                    break;
                case 2:
                    if (root == 0)
                        output += "0" + "\n";
                    else {
                        printmax(root);
                        root = Delete(root, maxval);
                    }
                    break;
                case 3:
                    if (root == 0)
                        output += "0" + "\n";
                    else {
                        printmin(root);
                        root = Delete(root, minval);
                    }
                    break;
            }
        }
    }
}

class node {
    int lc, rc; // 左右孩子
    int val, pri; // 值,优先级
    int num; // 重复个数
}

七 测试

 


版权声明:本文为chengqiuming原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。