JZOJ5456 奇怪的队列

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”也是满足题意的,但是字典序不是最小的。

Solution

  线段树维护区间空位数,将身高从小到大放入区间中,因为每次放入的数是剩下的数值中最小的,所以这个数前面和后面的空位数就是比这个数高的数量。因为字典序最小,所以判断从前和从后数第x个空位那种跟靠前,且判断空位是否足够。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 struct arr
 5 {
 6     int x,y;
 7 }a[200000];
 8 int n,l[500000],r[500000],s[500000],t[200000];
 9 int min(int x,int y)
10 {
11     if (x<y) return x;
12     return y;
13 }
14 int build(int x,int y,int w)
15 {
16     l[w]=x;r[w]=y;
17     s[w]=y-x+1;
18     if (x==y) return 0;
19     int mid=(x+y)/2;
20     build(x,mid,w*2);
21     build(mid+1,y,w*2+1);
22 }
23 int find(int x,int w)
24 {
25     if (l[w]==r[w])
26     {
27         s[w]--;
28         return l[w];
29     }
30     int p;
31     if (s[w*2]<x)
32         p=find(x-s[w*2],w*2+1);
33     else
34         p=find(x,w*2);
35     s[w]=s[w*2]+s[w*2+1];
36     return p;
37 }
38 int cmp(arr a,arr b)
39 {
40     return a.x<b.x;
41 }
42 int main()
43 {
44     scanf("%d",&n);
45     for (int i=1;i<=n;i++)
46         scanf("%d%d",&a[i].x,&a[i].y);
47     build(1,n,1);
48     sort(a+1,a+n+1,cmp);
49     for (int i=1;i<=n;i++)
50     {
51         int ss=min(a[i].y+1,n-i-a[i].y+1);
52         if (n-i-a[i].y+1<=0||ss>n-i+1)
53         {
54             printf("impossible");
55             return 0;
56         }
57         t[find(ss,1)]=a[i].x;
58     }
59     for (int i=1;i<=n-1;i++)
60         printf("%d ",t[i]);
61     printf("%d\n",t[n]);
62 }
View Code

 

  
 
posted @ 2018-08-14 21:27  kasiruto  阅读(265)  评论(0编辑  收藏  举报