POJ 1442 Black Box treap || 树状数组 || 优先队列

题目:

http://poj.org/problem?id=1442

题意:

给定n和m,表示有n个数往集合中插入,和m个输出。接下来是要插入的n个数,再然后是m个查询,对于某个查询b[i],意思是等到往集合中插入b[i]个数后查询第i小的数

思路

用treap直接一个一个插入就好,然后直接查询第i小,这是平衡树的看家本领,代码如下:

#include 
#include 
#include 
#include 

using namespace std;

const int N = 50000 + 10;

int a[N], b[N];

struct node
{
    int val, pri, son[2]; //pri是随机赋的优先级
    int sz;
    void init(int _val, int _pri, int _sz)
    {
        val = _val, pri = _pri, sz = _sz;
        son[0] = son[1] = 0;
    }
};
struct Treap
{
    int tot, root; //tot用来对结点计数,root是treap的根
    node tr[N];
    void init()
    {
        tot = 0, root = 0;
    }
    void update(int x)
    {
        tr[x].sz = tr[tr[x].son[0]].sz + tr[tr[x].son[1]].sz + 1;
    }
    void rotate(int &x, int p) //旋转,分左旋和右旋,p=0为左旋,p=1为右旋
    {
        int y = tr[x].son[!p];
        tr[x].son[!p] = tr[y].son[p];
        tr[y].son[p] = x;
        update(x); update(y);
        x = y;
    }
    //插入,根据要插入的值确定要插入当前的左右子树,插入完成后根据pri检查是否满足堆的性质,不满足的话进行旋转操作
    void insert(int &x, int val)
    {
        if(x == 0) tr[x = ++tot].init(val, rand(), 1);
        else
        {
            tr[x].sz++;
            int p = val > tr[x].val;
            insert(tr[x].son[p], val);
            if(tr[x].pri < tr[tr[x].son[p]].pri) rotate(x, !p);
        }
    }
    int kth(int x, int k) //寻找树中的第k小值
    {
        if(k == tr[tr[x].son[0]].sz + 1) return tr[x].val;
        if(k > tr[tr[x].son[0]].sz + 1) return kth(tr[x].son[1], k - tr[tr[x].son[0]].sz - 1);
        else return kth(tr[x].son[0], k);
    }
}treap;
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);

    treap.init();
    b[0] = 0;
    for(int i = 1; i <= m; i++)
    {
        scanf("%d", &b[i]);
        for(int j = b[i-1]+1; j <= b[i]; j++)
            treap.insert(treap.root, a[j]);
        printf("%d\n", treap.kth(treap.root, i));
    }
    return 0;
}

用树状数组的话,首先离散化数据,然后依次插入,维护前缀和,二分求第i小值

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 50000 + 10;

struct BIT
{
    int n, b[N];
    void init(int _n)
    {
        n = _n;
        memset(b, 0, sizeof b);
    }
    void add(int i, int x)
    {
        for(; i <= n; i += i & -i) b[i] += x;
    }
    int sum(int i)
    {
        int ans = 0;
        for(; i >= 1; i -= i & -i) ans += b[i];
        return ans;
    }
}bit;
int a[N], b[N], c[N];
int main()
{
    int n, m;
    while(~ scanf("%d%d", &n, &m))
    {
        bit.init(n);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        memcpy(c, a, sizeof a);
        sort(c + 1, c + 1 + n);
        for(int i = 1; i <= n; i++) a[i] = lower_bound(c + 1, c + 1 + n, a[i]) - c;
        b[0] = 0;
        int k = 0;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d", &b[i]);
            for(int j = b[i-1] + 1; j <= b[i]; j++) bit.add(a[j], 1);
            ++k;
            int l = 1, r = n, res;
            while(l <= r)
            {
                int mid = (l + r) >> 1;
                if(bit.sum(mid) >= k) res = mid, r = mid - 1;
                else l = mid + 1;
            }
            printf("%d\n", c[res]);
        }
    }
    return 0;
}

用优先队列也可以做,核心思想维护建两个优先队列,一个从小到大出队(队列1),一个从大到小出队(队列2),维护队列2中元素个数为i-1个,且为前i-1小,那么队列1中的队首就是第i小

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 50000 + 10;

int a[N], b[N];

int main()
{
    int n, m;
    while(~ scanf("%d%d", &n, &m))
    {
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);

        b[0] = 0;
        priority_queue<int, vector<int>, greater<int> > que1;
        priority_queue<int, vector<int>, less<int> > que2;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d", &b[i]);
            for(int j = b[i-1] + 1; j <= b[i]; j++)
            {
                que1.push(a[j]);
                while(! que2.empty() && que1.top() < que2.top())
                {
                    int tmp = que1.top(); que1.pop();
                    que1.push(que2.top()); que2.pop();
                    que2.push(tmp);
                }
            }
            printf("%d\n", que1.top());
            que2.push(que1.top()); que1.pop();
        }
    }
    return 0;
}

你可能感兴趣的:(树状数组,优先队列,treap)