Buy Tickets (线段树)

题目:Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…

The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.

It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!

People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.

大意:有n个人,每个人都被分配了可以插到第i个人的后面和一个数值,问经过n次插队后,最终按照队列顺序输出他们各自的数值。

思路:(感觉这题有点像前面的lost cow),如果从前往后遍历,那么前面的有可能被后面的人插队,所以我们先从后面往前推,因为这样有人的位置就固定了,不会改变。tr[u].sum代表tr[u].l到tr[u].r这个区间总共的座位。每次更新一下,如果那个位置小于它所要插进去的地方,那么就往右遍历,反之往左,最后pushup更新一下即可。

代码:

#include<algorithm>
#include<iostream>
using namespace std;
const int N=2e5+5;
struct node{
	int l,r;
	int sum;
}tr[N<<2];
int pos[N],val[N],ans[N];
void pushup(int u)
{
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void bt(int u,int l,int r)
{
	if(l==r){
		tr[u].l=tr[u].r=l;
		tr[u].sum=1;//初始化都为没人
	}
	else{
		int mid=l+r >> 1;
		bt(u<<1,l,mid);
		bt(u<<1|1,mid+1,r);
		pushup(u);
	}
}
void update(int u,int l,int r,int p,int v)
{
	if(l==r){
		ans[l]=v;
		tr[u].sum=0;//表示已经有人
	}
	else{
		int mid=l+r>>1;
		if(p<tr[u<<1].sum) update(u<<1,l,mid,p,v);//小于左边的空位置总和,说明可以左边可以插队
		else{
			update(u<<1|1,mid+1,r,p-tr[u<<1].sum,v);//往右遍历的时候需要减去左边的空位置
		}
		pushup(u);
	}
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		bt(1,1,n);
		for(int i=0;i<n;i++)
		{
			scanf("%d %d",&pos[i],&val[i]);
		}
		for(int i=n-1;i>=0;i--){
			update(1,1,n,pos[i],val[i]);
		}
		for(int i=1;i<n;i++)
		{
			printf("%d ",ans[i]);
		}
		printf("%d\n",ans[n]);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值