Loading

HDU-5493 Queue

Queue

n个人在排队,每个人的身高都不一样,同时每个人给出他前面比他高的人的数量,或者是他后面比他高的人的数量,要求构造一个排队的顺序(以身高作为代表),能够在满足以上条件的情况下字典序最小

树状数组 + 二分

可以直接用vector的insert做,但是会超时

为了保证字典序最小,我们首先将身高进行排序,然后一个个寻找位置插入,同时要保证插入的位置尽量往前

这个寻找的过程是可以用二分去查找的,因为如果当前位置不插入,则必然给当前选择的这个提供了一个前面比他高的人(因为是从矮到高插入的),如此看来这个值是一个不严格递增的,因此可以使用二分

为了更好地维护值的前缀和,引入树状数组来维护

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define pii pair<int, int>
const int maxn = 1e5 + 10;
int tr[maxn], n, ans[maxn];
pii num[maxn];

inline int lowbit(int x)
{
    return x & (-x);
}

void add(int x, int val)
{
    for (int i = x; i <= n; i += lowbit(i))
        tr[i] += val;
}

int query(int x)
{
    int ans = 0;
    for (int i = x; i; i -= lowbit(i))
        ans += tr[i];
    return ans;
}

int judge(int x)
{
    return x - query(x);
}

int main()
{
    int t;
    scanf("%d", &t);
    for (int casee = 1; casee <= t; casee++)
    {
        scanf("%d", &n);
        for (int i = 0; i <= n; i++)
            tr[i] = 0;
        for (int i = 0; i < n; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            num[i] = make_pair(a, b);
        }
        sort(num, num + n);
        bool flag = true;
        for (int i = 0; i < n; i++)
        {
            int l = 1, r = n, now = min(num[i].second, n - i - 1 - num[i].second);
            if (now < 0)
            {
                flag = false;
                break;
            }
            now++;
            while (l < r)
            {
                int mid = l + r >> 1;
                if (judge(mid) >= now)
                    r = mid;
                else
                    l = mid + 1;
            }
            add(l, 1);
            ans[l] = num[i].first;
        }
        printf("Case #%d:", casee);
        if (!flag)
            printf(" impossible");
        else
            for (int i = 1; i <= n; i++)
                printf(" %d", ans[i]);
        printf("\n");
    }
    return 0;
}
posted @ 2022-04-26 13:28  dgsvygd  阅读(27)  评论(0编辑  收藏  举报