poj2828 买票 线段树维护连续的区间

http://poj.org/problem?id=2828
题意:有n个人来排队
每一个来排队的人都站到自己想要站的位置上 在该位置以后的人 依次后退
问最后的排队序列
万万没有想到,本题是线段树。但它确实是。还是自己对线段树掌握的不够熟练
从第n个人往第一个人看,每一个人的位置是代表着他站完之后前方还有多少空位。
拿样例来看  
4
0 77
1 51
1 33
2 69          从第4个人看  第四个人进入是这样的  __ __ 69 __
  第三个人进入后这样    __ 33 69 __
  第二个人进入后        __ 33 69 51
  第一个人              77 33 69 51
知道这个 然后用线段树维护前方还有多少空位,每次插入,

找到对应的位置,储存,输出即可。

#include <set>
	#include <map>
	#include <queue>
	#include <stack>
	#include <deque>
	#include <math.h>
	#include <string>
	#include <vector>
	#include <stdio.h>
	#include <iostream>
	#include <string.h>
	#include <algorithm>
	#include <functional>
	#define mem(a) memset(a,0,sizeof(a));
	#define mem_1(a) memset(a,-1,sizeof(a));
	#define sf(a) scanf("%d",&a)
	#define sff(a,b) scanf("%d%d",&a,&b)
	#define sfff(a,b,c) scanf("%d%d%d",&a,&b,&c)
	#define lson l,mid,i<<1
	#define rson mid+1,r,i<<1|1
	const int INF = 0x7FFFFFFF;
	const int MAXN = 200100;
	const double PI = acos(-1.0);
	const double esp = 1e-10;
	using namespace std;
	int ans;
	int Ans[MAXN];
	struct xx
	{
  	  int pos,num;
	}data[MAXN];
	int cnt;
	struct node
	{
		int l,r,num,pos;
		int mid()
		{
		return (l+r)>>1;
		}
	}Tree[MAXN<<2];
	void build_tree(int l,int r, int i)
	{
	Tree[i].l = l;
	Tree[i].r = r;
	if(l == r)
	{
        Tree[i].num = 1;
        Tree[i].pos = cnt++;
		return ;
	}
		int mid = Tree[i].mid();
		build_tree(lson);
		build_tree(rson);
		Tree[i].num = Tree[i<<1].num + Tree[i<<1|1].num;
	}
	void updata_tree(int k,int i)
	{
		if(Tree[i].l == Tree[i].r)
		{
			Tree[i].num = 0;
			ans = Tree[i].pos;
			return ;
		}
		else
		{
			if(Tree[i<<1].num <=k) updata_tree(k - Tree[i<<1].num,i<<1|1);
			else updata_tree(k,i<<1);
		}
		Tree[i].num = Tree[i<<1].num + Tree[i<<1|1].num;
	}
	int main()
	{
		int n;
		while(sf(n)!=EOF)
		{
				for (int i = 1;i<=n; ++i)
			{
				sff(data[i].pos,data[i].num);
			}
			cnt = 1;
			build_tree(1,n,1);
			for(int i=n;i>=1;i--)
			{
				updata_tree(data[i].pos,1);
				Ans[ans] = data[i].num;
			}
			for(int i=1;i<n;i++)
			{
				printf("%d ", Ans[i]);
			}
			printf("%d\n", Ans[n]);
		}
		return 0;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值