http://acm.hdu.edu.cn/showproblem.php?pid=5493
思路:给定的人,按高度排个序,先判断impossible的情况,第i高的人k>=i,
然后就从高度最小的开始判断位置,
第i小的数,从左数对应第ki+1个空位置,方上hi,就行
排序后,对于第i高的人,比他高的人数一共是i-1个,前面要么是ki个人,后面是i-ki-1个人
要么后面是i-ki-1个人,前面要么是ki个人,前面高的人越少,小数越往前,字典序越小。
然后线段树找位置就可以了。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T,n,ans[100005],ok;
int tree[1000005];
void build(int rt,int l,int r)
{
if(l==r) {tree[rt]=1;return;}
int mid=(l+r)/2;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
return;
}
void query(int rt,int l,int r,int x,int h)
{
if(l==r) {tree[rt]=0;ans[l]=h;return;}
int mid=(l+r)/2;
if(tree[rt<<1]>=x) query(rt<<1,l,mid,x,h);
else query(rt<<1|1,mid+1,r,x-tree[rt<<1],h);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
return;
}
struct AA
{
int h,k;
bool operator<(const AA &aa) const
{
return h>aa.h;
}
}pos[100005];
int main()
{
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
ok=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&pos[i].h,&pos[i].k);
}
sort(pos+1,pos+1+n);
for(int i=1;i<=n;i++)
{
if(pos[i].k>=i)
{printf("Case #%d:",t);printf(" impossible\n");ok=1;break;}
}
if(ok) continue;
build(1,1,n);
for(int i=n;i>=1;i--)
{
if(i-pos[i].k-1<pos[i].k) pos[i].k=i-pos[i].k-1;///这里控制最小
query(1,1,n,pos[i].k+1,pos[i].h);
}
printf("Case #%d:",t);
for(int i=1;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}