题目描述

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. stack + positioned

    stack 下套container, 发现最大的显示,小的都没显示, 把所有都套个POSITIONED, 都正常显示了.

  2. Keepalived简单理解

    Keepalived Keepalived是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障.一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTE ...

  3. vue 关于子组件向父组件传值$emit触发无效问题

    先贴上代码 子组件代码 //子组件请求接口,用自己封装的axios getupdate(){ this.$post({ url:this.$apis.unitupdate, postType:'jso ...

  4. nginx mirror/post_action+gor实现https流量复制

    关于gor: 参考: https://www.cnblogs.com/jinjiangongzuoshi/p/11773070.html https://github.com/buger/gorepl ...

  5. sqlserver数据库的启动

    sqlserver实例几种启动的方法: (1)在WINDOWS服务控制台里手动启动,或者自动启动(默认) 第二种方式是SQLSERVER本身自已提供的启动方式,可以手动启动 (3)在SQLSERVER ...

  6. SQL SERVER-查询存储运行状态

    SELECT p.name as SPName, qs.last_elapsed_time as [LastExecTime(ms)], (total_elapsed_time as [AvgExec ...

  7. Oracle数据库 常用SQL

    -- 查询所有数据 SELECT * FROM [TABLE_NAME]; -- 查询数据总量 SELECT COUNT(*) AS COUNT FROM [TABLE_NAME]; -- 清空表内所 ...

  8. Go数据类型之复合数据类型--Slice

    3.2 Slice 一个slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象. 一个slice由三个部分构成:指针.长度和容量.指针指 ...

  9. springboot错误: 找不到或无法加载主类

    一:当在eclipse启动spring boot项目时出现问题: springboot错误: 找不到或无法加载主类 解决办法: 1,通过cmd命令行,进入项目目录进行,mvn clean instal ...

  10. python中的嵌套类

    python中的嵌套类 在.NET和JAVA语言中看到过嵌套类的实现,作为外部类一个局部工具还是很有用的,今天在python也看到了很不错支持一下.动态语言中很好的嵌套类的实现,应该说嵌套类解决设计问 ...