HDU 5493 Queue 【线段树】
<题目链接>
题目大意:
给你n个人的身高和他前面或者后面身高大于他的人的个数,求一个字典序最小的满足此条件的序列,如果不存在输出“impossible”。
解题分析:
因为要保证字典序最小,所以我们先将所有的人按身高排序,先给矮的人分配位置,并且位置尽可能的靠左。接下来就是分两种情况考虑,:
一:k个人在i前面,所以i的前面至少要留k个空格(因为是按从小到大分配人的位置,所以比i先插入的都是比他矮的);
二:k个人在i的后面,所以i的后面至少要留k个空格,所以i的前面需要留cnt-k个空格(cnt代表总的空格数,因为要按字典序最小,所以前面的空格越少越好,因为空格以后都是要放比i高的人)。
在上面两种情况中,选出i前面所需放的空格数最少的一种情况即可。
不过本题单纯的用线段树有点慢,可以考虑用二分+树状数组做。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define Lson rt<<1,l,mid 7 #define Rson rt<<1|1,mid+1,r 8 const int M = 1e5+10; 9 10 struct Node{ 11 int h,num; 12 }node[M]; 13 int sum[M<<2],val[M]; //val[]代表该点人的高度,sum[]代表该区间内的空格数 14 bool comp(Node x,Node y){return x.h<y.h;} 15 void Pushup(int rt){ 16 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 17 } 18 void build(int rt,int l,int r){ 19 if(l==r){ 20 sum[rt]=1; 21 return; 22 } 23 int mid=(l+r)>>1; 24 build(Lson); 25 build(Rson); 26 Pushup(rt); 27 } 28 void update(int rt,int l,int r,int cur,int h){ 29 if(l==r){ 30 val[l]=h; //更新该点的高度 31 sum[rt]=0; 32 return; 33 } 34 int mid=(l+r)>>1; 35 if(cur<=sum[rt<<1])update(Lson,cur,h); //如果左儿子区间中的空格数满足sum[rt<<1],那么就直接在左儿子区间内选择前面有p个空格的位置 36 else update(Rson,cur-sum[rt<<1],h); //如果左儿子中的空格数<cur,则需要到右儿子区间内查询前面有cur个空格的位置 37 Pushup(rt); 38 } 39 int main(){ 40 int T,n;scanf("%d",&T); 41 int ncase=0; 42 while(T--){ 43 scanf("%d",&n); 44 for(int i=1;i<=n;i++) 45 scanf("%d%d",&node[i].h,&node[i].num); 46 sort(node+1,node+1+n,comp); 47 build(1,1,n); 48 bool flag=false; 49 for(int i=1;i<=n;i++){ 50 int cnt=n-i; //剩余的空格数 51 int tmp=cnt-node[i].num; //此处表示将node[i].num个高的人放到i的后面,即i的后面要留node[i].num个人,因为总共有cnt个空格,即i的前面需要有cnt-node[i].num个空格 52 tmp=min(node[i].num,tmp); //因为要求字典序最小,所以在两种情况中选取i劲量靠前的方案,即选则在i前面至少要留的空格数最少的情况 53 if(tmp<0){ //不符合的情况 54 flag=true;break; 55 } 56 update(1,1,n,tmp+1,node[i].h); //寻找前面有tmp个空格的位置(因为要包括自己,所以是tmp+1) 57 } 58 printf("Case #%d: ",++ncase); 59 if(flag)printf("impossible\n"); 60 else{ 61 for(int i=1;i<=n;i++) 62 i==n?printf("%d\n",val[i]):printf("%d ",val[i]); 63 } } 64 return 0; 65 }
2018-11-03
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。