题意:
给你n个人的高度,
再给出一个值代表该高度下有前面比他高的 或 后面比他高的人数,
求满足条件下的最小字典序,
不行的话输出”impossible”
思路:
对于最小字典序,对于每个位置的最小是=min(k,n-i-k);
先离线排序一下,然后对每个人操作,如果(n-i-k)<0,二分找一下这个位置,然后存一下就好了;
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
struct asd{
int h;
int k;
};
asd q[N];
bool cmp(asd x,asd y)
{
return x.h<y.h;
}
int c[N];
int ans[N];
int n;
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int v)
{
while(x<=n+7)
{
c[x]+=v;
x+=lowbit(x);
}
}
int main()
{
int t;
int cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&q[i].h,&q[i].k);
sort(q+1,q+n+1,cmp);
memset(c,0,sizeof(c));
bool flag=true;
for(int i=1;i<=n;i++)
{
int p=min(q[i].k,n-i-q[i].k);
if((n-i-q[i].k)<0)
{
flag=false;
break;
}
p++;
int left,right;
left=1;
right=n;
while(left<right)
{
int mid=(left+right)/2;
if(mid-sum(mid)>=p)
right=mid;
else
left=mid+1;
}
add(left,1);
ans[left]=q[i].h;
}
printf("Case #%d:",cas++);
if(!flag)
printf(" impossible\n");
else
{
for(int i=1;i<=n;i++)
printf(" %d",ans[i]);
puts("");
}
}
return 0;
}