【NOIP2017提高A组冲刺】奇怪的队列

Description

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

Input

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

Output

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

Solution

这道题首先先要排序,然后就要用二分查答案,就可以了。

Code

#include<bits/stdc++.h>
#define rg register int
using namespace std;
int n,a[100005],b[100005],ans[100005],f[4000005];
int in()
{
	rg s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch<='9'&&ch>='0') s=s*10+ch-'0',ch=getchar();
	return s;
}
void out(rg x)
{
	if(x==0) return;
	out(x/10),putchar(x%10+'0');
}
void qsort(int l,int r)
{
	int i=l,j=r,mid=a[(l+r+1)/2];
	while(i<=j)
	{
		while(a[i]<mid) i++;
		while(a[j]>mid) j--;
		if(i<=j) swap(a[i],a[j]),swap(b[i],b[j]),i++,j--;
	}
	if(l<j) qsort(l,j);
	if(i<r) qsort(i,r);
}
void change(int y,int x,int l,int r)
{
	if(l>y||r<y) return;
	if(l==r)
	{
		f[x]++;
		return;
	}
	int mid=(l+r)/2;
	f[x]++;
	change(y,x*2,l,mid),change(y,x*2+1,mid+1,r);
}
int find(int sl,int sr,int l,int r,int x)
{
	if(sr<l||r<sl||r<l) return 0;
	if(sl<=l&&r<=sr) return f[x];
	int mid=(l+r)/2;
	return find(sl,sr,l,mid,x*2)+find(sl,sr,mid+1,r,x*2+1);
}
int lfind(int x,int l,int r)
{
	int now=(l+r)/2;
	if(l==r)
	{
		return l;
	}
	int fin=find(1,now,1,n,1);
	if(now-fin-x>1)
		return lfind(x,l,now);
	else if(now-fin-x<1)
		return lfind(x,now+1,r);
	else
		return now;
}
int rfind(int x,int l,int r)
{
	int now=(l+r)/2;
	if(l==r)
	{
		return l;
	}
	int fin=find(now,n,1,n,1);
	if(n-now-fin-x+1>1)
		return rfind(x,now+1,r);
	else if(n-now-fin-x+1<1)
		return rfind(x,l,now);
	else
		return now;
}
int main()
{
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	n=in();
	for(rg i=1;i<=n;i++) a[i]=in(),b[i]=in();
	qsort(1,n);
	rg tt,t;
	for(rg i=1;i<=n;i++)
	{
		if(n-i<b[i])
		{
			printf("impossible");
			return 0;
		}
		t=lfind(b[i],1,n),tt=rfind(b[i],1,n);
		while(ans[t]!=0) t--;
		while(ans[tt]!=0) tt++;
		if(t<1) t=99999;
		if(tt>n) tt=99999;
		ans[min(t,tt)]=a[i];
		change(min(t,tt),1,1,n);
	}
	for(rg i=1;i<=n;i++) out(ans[i]),putchar(32);
	return 0;
}
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值