题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5493
采用线段树也可解,本题解为树状数组
要字典序最小那么就要把身高排个序然后一个个插,每个人有两个可能位置,因为要求他前面的都比他矮,为了让字典序最小,就分给这个人一个较小的位置。注意要二分第i个人的位置, 然后用树状数组确定他前面有多少人以此得到空余的位置数
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
#include <functional>
using namespace std;
typedef long long ll;
const int N=1000+10;
const double PI=acos(-1.0);
const double EXP=1E-8;
const int INF=0x3f3f3f3f;
struct node
{
int h, k;
}a[100010];
int c[100010];
int ans[100010];
int n;
int lowbit(int x)
{
return x&-x;
}
void add(int x,int val)
{
while (x <= n)
{
c[x]+=val;
x += lowbit(x);
}
}
int getsum(int x)
{
int sum = 0;
while (x)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
bool cmp(node a, node b)
{
return a.h < b.h;
}
int main()
{
int t, cas = 0;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].h, &a[i].k);
memset(c, 0, sizeof c);
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++) add(i,1);
int flag = 1;
for (int i = 1; i <= n; i++)
{
int k = n - i,kk=a[i].k;
if (kk > k)
{
flag = 0;
break;
}
int temp = min(kk+1,k-kk+1);
int l = 1, r = n,ans1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (getsum(mid) >= temp)
{
ans1 = mid, r = mid - 1;
}
else l = mid + 1;
}
ans[ans1] = a[i].h;
add(ans1, -1);
}
if (!flag) printf("Case #%d: impossible\n",++cas);
else
{
printf("Case #%d:", ++cas);
for (int i = 1; i <= n; i++) printf(" %d", ans[i]);
printf("\n");
}
}
return 0;
}