Queue HDU - 5493

点击打开链接

 

每个人只记得前边或者后边有多少人比自己高 对于最高的人来说比他高的人不存在 次高的人最多有一个比他高 次次高的人最多有两个比他高。。。以此类推 只要有人超出这个范围就是impossible 而只要每个人都不超出这个范围 那这个队列一定存在(每个人都不超范围<=>队列存在)

因为题目给的条件是比某人高的人在其前或后有多少 且每个人的高度是唯一的 所以我们要按身高从低到高来考虑 这样才能推出每个人的正确位置

假设第i个人说他前或后有k个人比他高 先考虑k个人在前 那么在真正的队列中 这第i个人的前边 除去那些比他矮的人的位置 必须还要有k个位置留给那些比他高的 而先考虑k个人在后也是一样的道理

但是这样结果可能有很多 我们要按题目要求取字典序最小 即上述两种情况得出的位置取最小值即可

 

#include <bits/stdc++.h>
using namespace std;

struct node1
{
    int l;
    int r;
    int val;
    int id;
};

struct node2
{
    int h;
    int k;
    int id;
};

node1 tree[400010];
node2 per[100010];
int n,num;

bool cmp1(node2 n1,node2 n2)
{
    return n1.h<n2.h;
}

bool cmp2(node2 n1,node2 n2)
{
    return n1.id<n2.id;
}

void pushup(int cur)
{
    tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;
    return;
}

void build(int l,int r,int cur)
{
    int m;
    tree[cur].l=per[l].h;
    tree[cur].r=per[r].h;
    tree[cur].val=1;
    if(l==r)
    {
        tree[cur].id=num++;
        return;
    }
    m=(l+r)/2;
    build(l,m,cur*2);
    build(m+1,r,cur*2+1);
    pushup(cur);
    return;
}

int queryI(int tar,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        return tree[cur].id;
    }
    if(tar<=tree[cur*2].val) return queryI(tar,cur*2);
    else return queryI(tar-tree[cur*2].val,cur*2+1);
}

int queryII(int tar,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        return tree[cur].id;
    }
    if(tar<=tree[cur*2+1].val) return queryII(tar,cur*2+1);
    else return queryII(tar-tree[cur*2+1].val,cur*2);
}

void updateI(int tar,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        tree[cur].val--;
        return;
    }
    if(tar<=tree[cur*2].val) updateI(tar,cur*2);
    else updateI(tar-tree[cur*2].val,cur*2+1);
    pushup(cur);
    return;
}

void updateII(int tar,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        tree[cur].val--;
        return;
    }
    if(tar<=tree[cur*2+1].val) updateII(tar,cur*2+1);
    else updateII(tar-tree[cur*2+1].val,cur*2);
    pushup(cur);
    return;
}

int main()
{
    int t,cas,flag,i,l,r,p;
    scanf("%d",&t);
    for(cas=1;cas<=t;cas++)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&per[i].h,&per[i].k);
        }
        printf("Case #%d: ",cas);
        sort(per+1,per+n+1,cmp1);
        flag=1;
        for(i=n;i>=1;i--)
        {
            if(per[i].k>n-i)
            {
                printf("impossible\n");
                flag=0;
                break;
            }
        }
        if(!flag) continue;
        num=1;
        build(1,n,1);
        for(i=1;i<=n;i++)
        {
            per[i].k++;
            l=queryI(per[i].k,1),r=queryII(per[i].k,1);
            if(l<r)
            {
                per[i].id=l;
                updateI(per[i].k,1);
            }
            else
            {
                per[i].id=r;
                updateII(per[i].k,1);
            }
        }
        sort(per+1,per+n+1,cmp2);
        for(i=1;i<=n-1;i++)
        {
            printf("%d ",per[i].h);
        }
        printf("%d\n",per[i].h);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值