HDU-5493 Queue(线段树)

题意:

n n n个人排队,但是他们不清楚自己的位置,他们只知道自己的身高 h i h_i hi和队伍 前面或后面有多少人的身高比他们高(并不知道是前面还是后面)。 求一个合法的安排方案,并且该方案字典序最小。

题解:

先按照身高排序,从小到大依次安排位置,对于每个人,假设他前面或后面有k个人身高比他高,那么他的位置就必须要在从前往后的第 k + 1 k+1 k+1个空位置中或者从后往前的第 k + 1 k+1 k+1个空位置中,否则一定不满足,并且还要判断当前的空位置个数是否 ≥ k + 1 \geq k+1 k+1 。要求字典序最小,那么就判断这两种位置哪个靠前即可。求当前第 k k k个空位可以利用线段树解决。 ​

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=1e5+5;
const int inf=0x3f3f3f3f;
pii a[MAXN];
int ans[MAXN];
struct node
{
    int l,r;
    int sum;
}node[MAXN<<2];
void build(int l,int r,int num)
{
    node[num].l=l;
    node[num].r=r;
    if(l==r) 
    {
        node[num].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    node[num].sum=node[num<<1].sum+node[num<<1|1].sum;
}
void updata(int p,int num)
{
    if(node[num].l==node[num].r)
    {
        node[num].sum=1;
        return;
    }
    int mid=(node[num].l+node[num].r)>>1;
    if(p<=mid){
        updata(p,num<<1);
    }else{
        updata(p,num<<1|1);
    }
    node[num].sum=node[num<<1|1].sum+node[num<<1].sum;
}
int query1(int k,int num)
{
    if(node[num].l==node[num].r)
    {
        return node[num].l;
    }
    int mid=(node[num].l+node[num].r)>>1;
    int res1=(node[num<<1].r-node[num<<1].l+1)-node[num<<1].sum;
    int res2=(node[num<<1|1].r-node[num<<1|1].l+1)-node[num<<1|1].sum;
    if(res1>=k)
    {
        return query1(k,num<<1);
    }
    else if(res2>=k-res1) return query1(k-res1,num<<1|1);
    else return -1;
}
int query2(int k,int num)
{
    if(node[num].l==node[num].r)
    {
        return node[num].l;
    }
    int mid=(node[num].l+node[num].r)>>1;
    int res1=(node[num<<1].r-node[num<<1].l+1)-node[num<<1].sum;
    int res2=(node[num<<1|1].r-node[num<<1|1].l+1)-node[num<<1|1].sum;
    if(res2>=k)
    {
        return query2(k,num<<1|1);
    }
    else if(res1>=k-res2) return query2(k-res2,num<<1);
    else return -1;
}
int main()
{
    int t;
    scanf("%d",&t);
    int kase=1;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].first,&a[i].second);
        }
        sort(a+1,a+1+n);
        build(1,n,1);
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            int pos1=query1(a[i].second+1,1);
            int pos2=query2(a[i].second+1,1);
            if(pos1==-1){
                flag=1;
                break;
            }
            if(pos1<=pos2){
                updata(pos1,1);
                ans[pos1]=a[i].first;
            }else{
                updata(pos2,1);
                ans[pos2]=a[i].first;
            }
        }
        if(flag){
            printf("Case #%d: impossible\n",kase++);
        }else{
            printf("Case #%d: ",kase++);
            for(int i=1;i<=n;i++){
                if(i!=n) printf("%d ",ans[i]);
                else printf("%d\n",ans[i]);
            }
            //printf("\n");
        }
    }
}
posted @ 2021-07-21 16:43  TheBestQAQ  阅读(22)  评论(0)    收藏  举报