题目描述

nodgd的粉丝太多了,每天都会有很多人排队要签名。
  今天有n个人排队,每个人的身高都是一个整数,且互不相同。很不巧,nodgd今天去忙别的事情去了,就只好让这些粉丝们明天再来。同时nodgd提出了一个要求,每个人都要记住自己前面与多少个比自己高的人,以便于明天恢复到今天的顺序。
  但是,粉丝们或多或少都是有些失望的,失望使她们晕头转向、神魂颠倒,已经分不清楚哪一边是“前面”了,于是她们可能是记住了前面比自己高的人的个数,也可能是记住了后面比自己高的人的个数,而且他们不知道自己记住的是哪一个方向。
  nodgd觉得,即使这样明天也能恢复出一个排队顺序,使得任意一个人的两个方向中至少有一个方向上的比他高的人数和他记住的数字相同。可惜n比较大,显然需要写个程序来解决,nodgd很忙,写程序这种事情就交给你了。

输入格式

第一行输入一个整数n,表示指令的条数。(n<=100000,身高在整型范围)
  接下来n行,每行两个整数ai,bi,表示一个人的身高和她记住的数字,保证身高互不相同。

输出格式

输出一行,这个队列里从前到后的每个人的身高。如果有多个答案满足题意,输出字典序最小。如果不存在满足题意的排列,输出“impossible”

输入样例

4
  4 1
  3 1
  6 0
  2 0

输出样例

2 4 3 6
提示
  在所给出的答案队列中,第一个人身高为2,前面有0个人比他高,所以他是输入的第4个人;第二个人身高为4,右边有1个人比他高,所以他是输入的第1个人;第三个人身高为3,右边有1个人比他高,所以他是输入的第2个人;第四个人身高为6,左边有0个人比他高,所以他是输入的第3个人。
  显然,如果排列为“6 3 4 2”也是满足题意的,但是字典序不是最小的

分析

这个题的思路难以表述,可我还是要来强行口胡一波

考虑从小到大进行插入,因为这样可以在插入时贪心尽量控制字典序最小,即把当前的人尽量往前放。

我们先预处理出对于每个人,有多少个人比她高,如果比她高的人的个数小于她所记住的数则无解。

然后能够算出她前面最少有多少个人比她高,假设为k个

那么她插入时,因为是从小到大插入的,所以前面就应该预留k个空位给比她高的人,她就在第k+1个空位处

这样就既可以保证有解,还可以保证字典序最小。

但如果存在相同高度的人时,可能前面应该预留不止k个空格,因为后面的插入可能会占用某个空格却不作贡献

即如果两个人高度相同,k较大的人先插入,k较小的后插入,k较小的人就会破坏k较大的人所预留出来的空位

如图,1号的高度与2号相等,1号的k=5,2号的k=2

1号插入时给比她高的人留了k个空位

但是当2号插入时会占用一个空位却不作出贡献

而先插入2号再插入1号就不存在这样的问题

所以,遇到相同高度时就按k从小到大排序后在插入即可。

那么问题来了,我们如何来实现呢?

我们可以用树状数组来维护

每一个空格的值为1,这样某个位置的前缀和就是这个位置及之前共有多少个空位

显然越往右前缀和是单增的,所以可以二分确定第k个空位的位置

在插入一个人的时候,先二分出第k+1空位的位置,记录答案,然后在树状数组中修改这个位置的值,再去插入下一个人

复杂度为O(nlog^2n)。好像树状数组还有nlogn的做法,但我想咕了。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
int n,vis[],bit[],ans[];
struct node{int h,id;}st[];
void add(int x,int k){for(;x<=n;x+=(x&-x))bit[x]+=k;}
bool cmp(node a,node b){return a.h==b.h?a.id<b.id:a.h<b.h;}
int que(int x){int s=;for(;x;x-=(x&-x))s+=bit[x];return s;}
int main()
{
scanf("%d",&n);for(int i=;i<=n;i++)scanf("%d%d",&st[i].h,&st[i].id);
sort(st+,st++n,cmp);int flag=;
for(int i=,l,r;i<=n;add(i,),i++)
{
l=r=i;while(st[i].h==st[i+].h)i++,r++;
for(int j=l;j<=r;j++)flag|=(st[j].id=min(n-r-st[j].id,st[j].id))<;
}
if(flag)return puts("impossible"),;sort(st+,st++n,cmp);
for(int i=;i<=n;i++)
{
int l=,r=n,mid,pos;
while(l<=r)
{
mid=(l+r)>>;
if(que(mid)>=st[i].id+)r=mid-,pos=mid;
else l=mid+;
}
add(pos,-);
ans[pos]=st[i].h;
}
for(int i=;i<=n;i++)printf("%d%c",ans[i],i==n?'\n':' ');
}

【CSP模拟赛】奇怪的队列(树状数组 &二分&贪心)的更多相关文章

  1. 模拟赛 T3 DFS序+树状数组+树链的并+点权/边权技巧

    题意:给定一颗树,有 $m$ 次操作. 操作 0 :向集合 $S$ 中加入一条路径 $(p,q)$,权值为 $v$ 操作 1 :给定一个点集 $T$,求 $T$ 的并集与 $S$ 中路径含交集的权和. ...

  2. 【题解】Leyni,罗莉和队列(树状数组)

    [题解]Leyni,罗莉和队列(树状数组) HRBUST - 1356 将整个序列reverse一下,现在就变成了从高到低的排队.题目就变成了,定位一个妹子,问这个妹子前面的比这个妹子小的妹子中,下标 ...

  3. POJ 2182 Lost Cows 【树状数组+二分】

    题目链接:http://poj.org/problem?id=2182 Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  4. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  5. POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

    题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容 ...

  6. TZOJ 4602 高桥和低桥(二分或树状数组+二分)

    描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算“淹了两次”.举 ...

  7. 树状数组+二分||线段树 HDOJ 5493 Queue

    题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...

  8. P2161 [SHOI2009]会场预约[线段树/树状数组+二分/STL]

    题目描述 PP大厦有一间空的礼堂,可以为企业或者单位提供会议场地.这些会议中的大多数都需要连续几天的时间(个别的可能只需要一天),不过场地只有一个,所以不同的会议的时间申请不能够冲突.也就是说,前一个 ...

  9. The Stream of Corning 2( 权值线段树/(树状数组+二分) )

    题意: 有两种操作:1.在[l,r]上插入一条值为val的线段 2.问p位置上值第k小的线段的值(是否存在) 特别的,询问的时候l和p合起来是一个递增序列 1<=l,r<=1e9:1< ...

随机推荐

  1. 【洛谷 P2408】 不同子串个数(后缀自动机)

    题目链接 裸体就是身体. 建出\(SAM\),\(DAG\)上跑\(DP\),\(f[u]=1+\sum_{(u,v)\in DAG}f[v]\) 答案为\(f[1]-1\)(因为根节点没有字符) # ...

  2. 【layui】layer.photos 相册层动态生成Img 中出现的问题的解决方案

    layui版本:2.5.5 参照文档:https://www.jianshu.com/p/c594811fa882 他的3.8的解决方案有一些调整因为发现他的解决方式有些繁琐而最新的2.5.5版本中有 ...

  3. 修改redhat7默认显示语言从中文为英文

    [delmore@localhost Desktop]$ su                               //切换到最高权限 Password:                    ...

  4. Android多线程操作,as快捷键笔记

    Android studio 快捷键 cmd+p 快速查看该方法的参数定义 * * option + shift +上下 快速移动上下行 * * cmd + e 显示最近操作的文件 * * cmd + ...

  5. UGUI image

    1.创建UI->image 如何将图片在导入到场景中:将图片资源导入unity后,找到要导入的图片,将Texture Type改为“Sprite(2D and UI)”精灵模式,然后点击Appl ...

  6. array_reduce() 与 array_map()

    相似部分: 二者同为 处理数组函数,可遍历 数组中的每一个元素, 对其通过 function callback(){} 处理. 不同处: 参数: array_reduce( array, callba ...

  7. Linux之redis-cluster

    一,为什么要用redis-cluster 1.并发问题 redis官方生成可以达到 10万/每秒,每秒执行10万条命令假如业务需要每秒100万的命令执行呢? 2.数据量太大 一台服务器内存正常是16~ ...

  8. HQL基本语法及应用案例

    HQL基本语法及应用案例 摘自:<大数据技术体系详解:原理.架构与实践> 一.HQL基本语法 HQL是Hive提供的数据查询语言,由于Hive巨大的影响力,HQL已被越来越多的Hive O ...

  9. 渗透之路基础 -- 跨站伪造请求CSRF

    漏洞产生原因及原理 跨站请求伪造是指攻击者可以在第三方站点制造HTTP请求并以用户在目标站点的登录态发送到目标站点,而目标站点未校验请求来源使第三方成功伪造请求. XSS利用站点内的信任用户,而CSR ...

  10. Vue当中的this

    10事件绑定 methods当中的this就是Vue实例对象vm var vm = new Vue({ el: '#app', data: { num: 0 }, // 注意点: 这里不要忘记加逗号 ...