思路:显然的要字典序最小那么就离线先把身高排个序然后一个个插,对于某一个人来说,他的位置有可能在p[i].h+1,或者n-i-p[i].h+1这两个位置,然后二分前面有多少个位置来插入就可以了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+7;
int c[maxn],ans[maxn];
int lowbit(int x){return x&(-x);}
void update(int i,int v)
{
while(i<=maxn)
{
c[i]+=v;
i+=lowbit(i);
}
}
int query(int i)
{
int ans = 0;
while(i)
{
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
struct P
{
int h,pos;
}p[maxn];
bool cmp(P a,P b)
{
return a.h<b.h;
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
memset(c,0,sizeof(c));
int n;
scanf("%d",&n);
for(int i = 1;i<=n;i++)
scanf("%d%d",&p[i].h,&p[i].pos);
sort(p+1,p+1+n,cmp);
int flag = 0;
for(int i = 1;i<=n;i++)
{
int k = min(p[i].pos,n-i-p[i].pos);
if(k<0)
{
flag=1;
break;
}
k++;
int l = 1,r=n;
int re = 0;
while(l<=r)
{
int mid = (l+r)>>1;
if(mid-query(mid)>=k)r=mid-1,re =mid;
else l = mid+1;
}
update(re,1);
ans[re]=p[i].h;
}
printf("Case #%d: ",cas++);
if(flag)
printf("impossible\n");
if(!flag)
for(int i = 1;i<=n;i++)
{
if(i==n)
printf("%d\n",ans[i]);
else
printf("%d ",ans[i]);
}
}
}