hdu 4446

官方题解

1.一开始开2个队列a,ba为答案队列,b为临时队列

2.找出当最小的C值为C[k](相同时取k最小的)

a)C[k]=0:将k加入a-k加入b。在C序列中删除元素C[k],并将C[1]C[k-1]减一。

b)C[k]>0:将b队首的元素p取出加入a,并将C[-p+1]c[n]减一。

重复做直到所有元素进入a或者b

3.将b接在a后面,倒序就是答案序列

无解有两种情况:

1C中出现了负数。

2.出现2b情况时b为空

#include <iostream>
#include <cstdio>
#include <cstring>
#define ls (t<<1)
#define rs (t<<1|1)
#define midt (tr[t].l+tr[t].r>>1)
using namespace std;
const int maxn=1e5+9;
const int inf=1111111;
int ans[maxn<<1],que[maxn<<1];
int a[maxn];

struct
{
    int l,r,min,lazy,id;
}tr[maxn<<2];

void pushdown(int t)
{
    if(tr[t].lazy)
    {
        tr[ls].min+=tr[t].lazy;
        tr[rs].min+=tr[t].lazy;
        tr[ls].lazy+=tr[t].lazy;
        tr[rs].lazy+=tr[t].lazy;
        tr[t].lazy=0;
    }
}


void maketree(int t,int l,int r)
{
    tr[t].l=l;
    tr[t].r=r;
    tr[t].lazy=0;
    if(l==r)
    {
        tr[t].min=a[l];
        tr[t].id=l;
        return ;
    }
    int mid=midt;
    maketree(ls,l,mid);
    maketree(rs,mid+1,r);
    if(tr[ls].min<=tr[rs].min)
    {
        tr[t].min=tr[ls].min;
        tr[t].id=tr[ls].id;
    }
    else
    {
        tr[t].min=tr[rs].min;
        tr[t].id=tr[rs].id;
    }
}

void modify(int t,int l,int r,int tmp)
{
    if(tr[t].l==l&&tr[t].r==r)
    {
        tr[t].min+=tmp;
        tr[t].lazy+=tmp;
        return ;
    }
    pushdown(t);
    int mid=midt;
    if(r<=mid) modify(ls,l,r,tmp);
    else if(mid+1<=l) modify(rs,l,r,tmp);
    else
    {
        modify(ls,l,mid,tmp);
        modify(rs,mid+1,r,tmp);
    }

    if(tr[ls].min<=tr[rs].min)
    {
        tr[t].min=tr[ls].min;
        tr[t].id=tr[ls].id;
    }
    else
    {
        tr[t].min=tr[rs].min;
        tr[t].id=tr[rs].id;
    }
}

int querymin()
{
//    cout<<tr[1].min<<endl;
    if(tr[1].min==0)
    return tr[1].id;
    else return -1;
}

int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        int st=1,ed=0,lon=2*n;
        bool flage=1;
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        maketree(1,1,n);
        for(int i=1;i<=n;i++)
        {
            int tmp;
            while(querymin()==-1)
            {
                if(st<=ed)
                {
                    ans[lon--]=-que[st];
                    if(que[st]+1<=n)
                    modify(1,que[st]+1,n,-1);
                    st++;
                }
                else
                {
                    flage=0;
                    break;
                }
            }
            if(!flage) break;
            tmp=querymin();
            ans[lon--]=tmp;
            que[++ed]=tmp;
            if(1<=tmp-1)
            modify(1,1,tmp-1,-1);
            modify(1,tmp,tmp,inf);
        }
        if(!flage)
        {
            printf("Impossible\n");
        }
        else
        {
            while(st<=ed)
            {
                ans[lon--]=-que[st++];
            }
            for(int i=1;i<=n*2;i++)
            printf("%d ",ans[i]);
            printf("\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值