poj2828

12 篇文章 0 订阅
6 篇文章 0 订阅

题目有难度,线段树。

大致题意:按顺序给定n个人插队时其前方人的个数,并同时给定每个人的ID,令队首元素是第一个人,其前方人个数为0,现在要求按排队的顺序依次输入最终队列的人的编号。

题意很明确。

分析如下:

可令线段树节点结构如下:

struct Node{
 int l,r,value,pos;
}node[Max*3];

其中value为该区间范围内还空余的位置个数,而pos为单位区间的坐标,则有如下式子成立:令输入为d,v

1)若d+1大于node[Lson(po)].value,则应该插入右节点,且权值减少node[Lson(po)].value

2)若d+1小于或等于node[Lson(po)].value,则因该插入左节点

下面是代码:10724K+1500MS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 200010
#define Lson(p) (p<<1)
#define Rson(p) (p<<1|1)
#define Mid(a,b) ((a+b)>>1)
struct Node{
	int l,r,value,pos;
}node[Max*3];
int Input[Max][2];
int ans[Max];
int n;
void build_tree(int left,int right,int po){ //创建线段树,注意value为给区间还空余的位置,初始时即为区间长度
	node[po].l=left,node[po].r=right,node[po].value=right-left+1;
	if(left==right){
		node[po].pos=left;
		return ;
	}
	int mid=Mid(left,right);
	build_tree(left,mid,Lson(po));
	build_tree(mid+1,right,Rson(po));
}
void update_tree(int d,int v,int po){ //更新线段树,同时确定最终队列位置
	node[po].value--;
	if(node[po].l==node[po].r){ // 若找到最终队列位置
		ans[node[po].pos]=v; // 赋值编号
		return ;
	}
	if(d>node[Lson(po)].value) //若大于还剩余的空位置,则在右儿子
		update_tree(d-node[Lson(po)].value,v,Rson(po));
	else //否则在左儿子
		update_tree(d,v,Lson(po));
}
int main(){
	while(scanf("%d",&n)!=EOF){
		build_tree(1,n,1); //建树,区间为1——n
		for(int i=1;i<=n;i++){ //输入n个人插队信息和个人ID
			scanf("%d%d",&Input[i][0],&Input[i][1]);
			Input[i][0]++; //增加1
		}
		for(int i=n;i>=1;i--) //逆序更新线段树
			update_tree(Input[i][0],Input[i][1],1);
		for(int i=1;i<=n;i++) //按1——n位置输出ID
			printf("%d ",ans[i]);
		printf("\n");
	}
	return 0;
}



 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值