hdu5493 树状数组+二分

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

利用二分找到前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=0;
    for(int i=x;i;i-=i&-i)
        res+=bit[i];
    return res;
}

int main(){
    int t,flag;
    scanf("%d",&t);
    for(int tt=1;tt<=t;tt++){
        scanf("%d",&n);
        memset(bit,0,sizeof bit);
        flag=0;
        for(int i=1;i<=n;i++) add(i,1);
        for(int i=1;i<=n;i++)scanf("%d%d",&p[i].h,&p[i].k);
        sort(p+1,p+1+n,cmp); 
        for(int i=1;i<=n;i++){
            int pos1=p[i].k+1,pos2=n-i-p[i].k+1;
            if(pos2<=0){
                 flag=1;
                 break;
            }
            int pos=min(pos1,pos2);//为了字典序最小找一个最小的位置 
            int l=1,r=n,mid,anss;
            while(l<=r){
                mid=l+r>>1;
                if(query(mid)<pos)
                    l=mid+1;
                else anss=mid,r=mid-1;
            }
            add(anss,-1);
            ans[anss]=p[i].h;
        }
        if(flag)printf("Case #%d: impossible\n",tt);
        else {
            printf("Case #%d:",tt);
            for(int i=1;i<=n;i++) printf(" %d",ans[i]);
            puts("");
        }
    } 
    return 0; 
} 

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10147363.html