hdoj5493【树状数组+二分】

来源:互联网 发布:c 语言培训 编辑:程序博客网 时间:2024/06/10 08:18

题意:
给你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;}
0 0
原创粉丝点击