题意:n(<1e5)个人站队,身高num,每个人记得前面或者后面有x人比他高,问原来的身高是怎样的,输出最小的排序
题解:对于第i高的人,前面有min(x,n-x-i)个人比他高
于是我们可以从低到高为他们安排位置
可以用树状数组维护,到某个点时,前面还有多少个空位置
然后二分,查找刚好有min(x,n-x-i)+1个空位置的点,放进去这个人就可以
///num表示身高,x表示前面或后面有多少人比他高
struct po{
int num,x;
}p[100010];
bool cmp(po a, po b){
return a.num < b.num;
}
int b[100010],n;
int ans[100010];
int sum(int x){
int ans=0;
while(x>0){
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int sum){
while(x<=n){
b[x]+=sum;
x+=lowbit(x);
}
}
int main(){
int t;
cin>>t;
for(int ii=1;ii<=t;ii++){
scanf("%d",&n);
memset(b,0,sizeof(b));
memset(ans,-1,sizeof(ans));
for(int i=1;i<=n;i++){
scanf("%d %d",&p[i].num,&p[i].x);
}
sort(p+1,p+n+1,cmp);
///初始每个位置都是空的
for(int i=1;i<=n;i++){
add(i,1);
}
bool bool1=true;
for(int i=1;i<=n;i++){
///由于已经排好序,那么当前身高人放在越前越好,所以找最小值,注意可能为负
if(n-p[i].x-i>=0){
p[i].x=min(p[i].x,n-p[i].x-i);
}
///如果比他高的人大于等于当前所有的空位置,那么肯定没有符合的情况
if(sum(n)<=p[i].x){
bool1=false;
break;
}
p[i].x++;
int l=1,r=n,xx=0;
while(l<r){
int mid=(l+r)/2;
int temp=sum(mid);
if(temp==p[i].x && ans[mid]==-1){
xx=mid;
break;
}
///如果当前空位置数等于比他高的人+1,并且当前位置已经有人了,那么对应的空位置肯定出现在前面
else if(temp==p[i].x){
r=mid-1;
}
else if(temp<p[i].x){
l=mid+1;
}
else {
r=mid-1;
}
}
if(xx==0)
xx=r;
ans[xx]=p[i].num;
add(xx,-1);
}
if(!bool1)
printf("Case #%d: impossible\n",ii);
else {
printf("Case #%d:",ii);
for(int i=1;i<=n;i++){
printf(" %d",ans[i]);
}
cout<<endl;
}
}
return 0;
}