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;
}