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

 

  
 

转载于:https://www.cnblogs.com/Tokisaki-Kurumi/p/9478009.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值