poj 2828 Buy Tickets

题目链接:http://poj.org/problem?id=2828

这个题目主要是考虑从后往前填,这样就方便操作了。

其中peo[rt]表示以rt为根的左右子树中总共存在的空位数,其实每个元素的pos[i]就可以表示前面有pos[i]个空位,这样就可以进行插入了。

代码中有解释的,很容易看懂。

#include <iostream>
#include <cstdio>

using namespace std;

#define lson l,m,rt<<1   //预定义左儿子
#define rson m+1,r,rt<<1|1  //预定义右儿子

const int maxx=200002;

int peo[maxx<<2],ord[maxx];//ord表示最后插入完成后的数值序列
int v[maxx],pos[maxx];//pos表示的是输入时要插入的位置 v表示刚输入时pos对应的数值

void build(int l,int r,int rt){
	peo[rt]=r-l+1;//刚建树时,全是空位 所以peo[rt]=r-l+1;
	if(l==r){
		return ;
	}
	int m=(l+r)>>1; 
	build(lson);
	build(rson);
}

void update(int p,int va,int l,int r,int rt){
	peo[rt]--;   //肯定其表示的范围中空位数减1
	if(l==r){
		ord[l]=va; //l或r即是要插入数值的下标位置
		return ;
	}
	int m=(r+l)>>1;
	if(p<=peo[rt<<1])update(p,va,lson); //p表示前面应该有的空位数
	else{
		p-=peo[rt<<1];//如果要插到右孩子区间则他的空位数应该算上做孩子中已有的空位数
		update(p,va,rson);
	}
}

int main(){
	int n,i;
	while(scanf("%d",&n)!=EOF){
		build(1,n,1);
		for(i=1;i<=n;i++){
			scanf("%d%d",&pos[i],&v[i]);
			pos[i]++;
		}
		for(i=n;i>=1;i--){
			update(pos[i],v[i],1,n,1);
		}
		printf("%d",ord[1]);
		for(i=2;i<=n;i++){
			printf(" %d",ord[i]);
		}
		printf("\n");
	}
	return 0;
}

微笑ok!

你可能感兴趣的:(Build)