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