线段树 HDU - 5493 加贪心

来源:互联网 发布:163邮箱群发软件 编辑:程序博客网 时间:2024/06/14 22:52

H - Queue HDU - 5493
一个完全不知道怎么下手的题。题意就是有一个队伍,然后将他们打散,他们只记得他们前面或后面比他们高的人有k个,问他们之前的排序,如果不止一个的话,输出最小字典序的一个。怎么做?这里线段树维护的是可以存放的位置。我们先对h进行一个排序,因为身高比较小的也不会影响k的值,然后我们再讲h一个一个插到线段树里。这里需要注意的 一点是我们选一下是前面高的人为k个还是后面高的人为k个。根据贪心与字典序,我们可以选一个使当前节点之前的人数最少。

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>using namespace std;#define maxn 100005struct node{    int h,k;    bool operator <(const node &t)const {        return h<t.h;    }};node a[maxn];struct tree{    int l,r,val;};int ans[maxn];//存answertree d[maxn<<2];void buildtree(int i,int l,int r){    d[i].l=l,d[i].r=r,d[i].val=r-l+1;    if(l==r)        return;    int mid=(l+r)>>1;    buildtree(i<<1,l,mid);    buildtree(i<<1|1,mid+1,r);}void Insert(int i,int num,int v){    if(d[i].l==d[i].r)    {        d[i].val=0;        ans[d[i].l]=v;//这里是要输出的答案,并不一是存的时候是按顺序的        return;    }    if(d[i<<1].val>=num) Insert(i<<1,num,v);    else  Insert(i<<1|1,num-d[i<<1].val,v);//这里要比较注意,先是不能写成 else if(d[i<<1|1].val>=num),因为它到d[i<<1|1]是因为d[i]的左边进不去,左边的空位不足,这时num就变成了num-d[i<<1].val    d[i].val=d[i<<1].val+d[i<<1|1].val;}int main(){    int T;    scanf("%d",&T);    int temp=T;    while(T--)    {        memset(d,0,sizeof(d));        memset(a,0,sizeof(a));        memset(ans,0,sizeof(ans));        int n;        scanf("%d",&n);        for(int i=1;i<=n;i++)        {            scanf("%d %d",&a[i].h,&a[i].k);        }        sort(a+1,a+n+1);        buildtree(1,1,n);        bool f=0;        for(int i=1;i<=n;i++)        {            int c=n-i,p;//c是代表这个队伍还可以插多少人           if(a[i].k>c)//如果剩余的空位比k小的话,就是不可能的情况           {               f=1;               break;           }           p=min(a[i].k,c-a[i].k);//它前面最少有多少人           Insert(1,p+1,a[i].h);        }        printf("Case #%d:",temp-T);        if(f) printf(" impossible\n");        else        {            for(int i=1;i<=n;i++)                printf(" %d",ans[i]);            printf("\n");        }    }}
0 0
原创粉丝点击