传送门
题解:
因为有限制的是比当前人更高的人才有限制。所以如果之前安排的人都比这个人的身高低的话那么不会造成任何贡献。所以相当于按照空位插空,如果需要安排的人数大于空位数显然是无解的。空位数用树状数组存,因为位置越向右前面被占的位置越多,留下的空位越少,所以具有二分性。
那么就有两种情况,一种是插左边,那么空位数就需要num+1个,如果之前的人和比他高的人都插右边的话就需要n-i-num+1个。取min就满足字典序最小了。
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n;
#define lowbit(x) x&(-x)
struct Node{
int h,num,postion;
}node[N];
int cmp(Node a,Node b)
{
return a.h<b.h;
}
int tr[N];
void add(int x)
{
while (x<N){
tr[x]+=1;
x+=lowbit(x);
}
}
int ask(int x)
{
int sum=0;
while(x){
sum+=tr[x];
x-=lowbit(x);
}
return sum;
}
int work(int x)
{
if(x<0) return -1;
int res,l=1,r=n;
while(l<=r){
int mid=l+r>>1;
if(mid-ask(mid)<x) l=mid+1;
else r=mid-1;
}
return l;
}
int cmp2(Node a,Node b)
{
return a.postion<b.postion;
}
void init()
{
memset(tr,0,sizeof tr);
}
signed main()
{
int t,cas=1;
scanf("%d",&t);
while(t--){
init();
printf("Case #%d: ",cas++);
int flag=0; scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&node[i].h,&node[i].num);
sort(node+1,node+1+n,cmp);
for(int i=1;i<=n;i++){
int pos=n-i+1;
if(node[i].num>=pos){
flag=1;
break;
}
int x1=work(node[i].num+1);
int x2=work(n-node[i].num-i+1);
node[i].postion=min(x1,x2);
add(node[i].postion);
}
if(flag){
puts("impossible");
continue;
}
sort(node+1,node+1+n,cmp2);
for(int i=1;i<=n;i++) printf("%d%c",node[i].h,i==n?'\n':' ');
}
}