题目描述

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. Jsp页面显示时间:<fmt>标签问题

    <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"%> <%@ taglib ...

  2. SQL Server修改表的模式schema

    use myDBgo create schema myschema --先建立go alter schema myschema transfer dbo.myTable --移动对象至建立的schem ...

  3. npm/svn 命令

    npm npm config set registry https://registry.npm.taobao.org npm config list svn + 清除失败的事务 - cmd管理员运行 ...

  4. springboot超级详细的日志配置(基于logback)

    前言   java web 下有好几种日志框架,比如:logback,log4j,log4j2(slj4f 并不是一种日志框架,它相当于定义了规范,实现了这个规范的日志框架就能够用 slj4f 调用) ...

  5. SIM7500 SIM7600 SIM800 HTTP

    解释 //Start HTTP service AT+HTTPINIT //Stop HTTP service AT+HTTPTERM //Set HTTP Parameters value /* & ...

  6. 191010 python3分解质因数

    # 题目:将一个正整数分解质因数.例如:输入90,打印出90=2*3*3*5.# 程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:# (1)如果这个质数恰等于n,则说明分解 ...

  7. Python itchat模块的使用,利用图灵机器人进行微信消息自动回复

    一.下载安装itchat模块 二.小实验:获取微信好友头像信息 这需要用itchat模块中的一个方法 itchat.get_friends()#获取微信所有微信好友信息 现在我们导入itchat,打印 ...

  8. VMware安装ubantu

    下载ubantu镜像文件: http://mirror.pnl.gov/releases/xenial/ http://mirrors.melbourne.co.uk/ubuntu-releases/ ...

  9. C++(三十五) — 运算符重载

    运算符重载的实质:函数重载.除了增加一个关键字 operator 外,与函数重载没有区别,都是通过该类的某个对象来访问重载运算符. (1)重载运算符时,运算符运算顺序和优先级不变,操作数个数不变: ( ...

  10. git 在本地备份与指定不需要管理文件

    git 在本地备份 备份文件夹操作 在本地备份文件夹克隆一个不带工作区的仓库: 哑协议: git clone --bare <workspace>/.git yourwork.git gi ...