hdu5493 树状数组+二分

时间:2020-12-11 21:50:18

数字的字典序,,有点迷,网上看题解也没有明说,总之越大的数字放在后面就行了

利用二分找到前k个空位即可

/*
每个人有一个独特的高度,第i个人高hi,前面有ki个人比他高或后面有ki个人比他高
请求出可能队列, 升序排列身高,每个人可选的位置是第k+1个空位或者第n-i-k个空位,
如果n-i-k<=0,那么就是impossible
结果要按照字典序输出,所以如果有两个可选位置可以插入时,需要判断从前往后插还是从后往前插好。
插入时按照二分找到树状数组中第k+1个空位
离线离散化,树状数组维护空位
复杂度O(nlognlogn)
*/
#include<bits/stdc++.h>
#define maxn 100005 using namespace std; struct node{int h,k;}p[maxn];
int cmp(node a,node b){return a.h<b.h;}
int bit[maxn],ans[maxn],n;
void add(int x,int num){
for(int i=x;i<=n;i+=i&-i)
bit[i]+=num;
}
int query(int x){
int res=;
for(int i=x;i;i-=i&-i)
res+=bit[i];
return res;
} int main(){
int t,flag;
scanf("%d",&t);
for(int tt=;tt<=t;tt++){
scanf("%d",&n);
memset(bit,,sizeof bit);
flag=;
for(int i=;i<=n;i++) add(i,);
for(int i=;i<=n;i++)scanf("%d%d",&p[i].h,&p[i].k);
sort(p+,p++n,cmp);
for(int i=;i<=n;i++){
int pos1=p[i].k+,pos2=n-i-p[i].k+;
if(pos2<=){
flag=;
break;
}
int pos=min(pos1,pos2);//为了字典序最小找一个最小的位置
int l=,r=n,mid,anss;
while(l<=r){
mid=l+r>>;
if(query(mid)<pos)
l=mid+;
else anss=mid,r=mid-;
}
add(anss,-);
ans[anss]=p[i].h;
}
if(flag)printf("Case #%d: impossible\n",tt);
else {
printf("Case #%d:",tt);
for(int i=;i<=n;i++) printf(" %d",ans[i]);
puts("");
}
}
return ;
}