Queue HDU - 5493

原题链接
考察:二分+树状数组
只想到了暴力做法...最关键的从左往右和从右往左取min没想到.
思路:
  队列模拟成n个空位,因为只需要考虑比当前高的,且按字典序,我们将身高排序,对于\(h_i\),有&k_i&个比他高的
(1)如果在前面,那么他的位置是第\(k_i+1\)个空位
(2)如果在后面,位置在\(n-k_i-i+1\)个空位.
  想到这就直接树状数组+二分了,对于矛盾情况就是对于第\(i\)个人,\(k>n-i\)

Code

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,tr[N],ans[N];
struct People{
    int h, k;
    bool operator<(const People& p)const{
        return this->h < p.h;
    }
}p[N];
int lowbit(int x)
{
    return x & -x;
}
void add(int k,int x)
{
    for (int i = k; i <= n;i+=lowbit(i))
        tr[i] += x;
}
int query(int k)
{
    int sum = 0;
    for (int i = k; i;i-=lowbit(i))
        sum += tr[i];
    return sum;
}
int find(int k)
{
    int l = 1, r = n;
    while(l<r)
    {
        int mid = l + r >> 1;
        if(query(mid)>=k)
            r = mid;
        else
            l = mid + 1;
    }
    return r;
}
int main()
{
    int T, kcase = 0;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        memset(tr, 0, sizeof tr);
        bool ok = 1;
        for (int i = 1; i <= n;i++)
        {
            scanf("%d%d", &p[i].h, &p[i].k);
            add(i, 1);
            ans[i] = 0;
        }
        sort(p + 1, p + n + 1);
        for (int i = 1; i <= n;i++)
        {
        	if(n-i<p[i].k)
            {
            	ok = 0;
            	break;
			}
            int a = find(p[i].k + 1);
            int b = find(n - p[i].k - i + 1);
            int c = min(a, b);
            add(c, -1);
            ans[c] = p[i].h;
        }
        printf("Case #%d:", ++kcase);
        if(!ok)
        {
            puts(" impossible");
            continue;
        }
        for (int i = 1; i <= n;i++)
            printf(" %d", ans[i]);
        printf("\n");
    }
    return 0;
}

posted @ 2021-07-04 23:44  acmloser  阅读(32)  评论(0编辑  收藏  举报