[JZOJ5456]【NOIP2017提高A组冲刺11.6】奇怪的队列

Description

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

Input

第一行输入一个整数𝑛,表示指令的条数。
接下来𝑛行,每行两个整数𝑎𝑖,𝑏𝑖,表示一个人的身高和她记住的数字,保证身高互不相同。

Output

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

Sample Input

输入1:
4
4 1
3 1
6 0
2 0
输入2:
6
1 5
8 0
3 1
4 0
2 0
6 0

Sample Output

输出1:
2 4 3 6
输出2:
1 2 4 3 6 8
 

Data Constraint

n<=100000
ai<=10^9
 

Hint

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

 

 


 

 

按身高从小到大排序, 然后得到他的rank, 要不插在队伍前面数第rank+1个空位, 要不就插在从后数的第rank+1位,因为要字典序最小, 所以找到最小的位置插入他。

然后上面的查询操作可以用线段树快速实现。

总复杂度O(NlogN)。

没有输出impossble挂了10分,AK的梦想破灭了233

 


 

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define reg register
inline int read() {
    int res=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
    return res;
}
#define N 100005
int n;
int tr[N<<2];
#define ls(o) o << 1
#define rs(o) o << 1 | 1

inline void update(int o)
{
    tr[o] = tr[ls(o)] + tr[rs(o)];
}

void Build(int l, int r, int o)
{
    if (l == r)
    {
        tr[o] = 1;
        return ;
    }
    int mid = l + r >> 1;
    Build(l, mid, ls(o));
    Build(mid + 1, r, rs(o));
    update(o);
}

void change(int l, int r, int o, int pos)
{
    if (l == r) {tr[o] = 0; return ;}
    int mid = l + r >> 1;
    if (pos <= mid) change(l, mid, ls(o), pos);
    else change(mid + 1, r, rs(o), pos);
    update(o);
}

int query(int l, int r, int o, int k)
{
    if (l == r) return l;
    int mid = l + r >> 1;
    if (tr[ls(o)] >= k) return query(l, mid, ls(o), k);
    else return query(mid + 1, r, rs(o), k - tr[ls(o)]);
}

struct date {
    int h, id;
}p[N];

bool cmp(date a, date b)
{
    return a.h < b.h;
}

int ans[N];

int main()
{
    freopen("queue.in", "r", stdin);
    freopen("queue.out", "w", stdout);
    n = read();
    for (reg int i = 1 ; i <= n ; i ++) p[i].h = read(), p[i].id = read();
    sort(p + 1, p + 1 + n, cmp);
    Build(1, n, 1);
//    for (reg int i = 1 ; i <= n ; i ++) printf("%d\n", p[i].h);
    for (reg int i = 1 ; i <= n ; i ++)
    {
        int k1 = query(1, n, 1, p[i].id + 1);
        int k2 = query(1, n, 1, n - p[i].id - i + 1);
        if (k1 <= k2) 
        {
            ans[k1] = p[i].h;
            change(1, n, 1, k1);
        }
        else {
            ans[k2] = p[i].h;
            change(1, n, 1, k2);
        }
    }
    for (reg int i = 1 ; i <= n ; i ++) printf("%d ", ans[i]);
    return 0;
}

 

posted @ 2018-08-14 19:14  zZhBr  阅读(221)  评论(2编辑  收藏  举报