Lost Cows POJ - 2182(线段树)

题目

N (2 <= N <= 8,000) cows have unique brands in the range 1…N. In a spectacular display of poor judgment, they visited the neighborhood ‘watering hole’ and drank a few too many beers before dinner. When it was time to line up for their evening meal, they did not line up in the required ascending numerical order of their brands.

Regrettably, FJ does not have a way to sort them. Furthermore, he’s not very good at observing problems. Instead of writing down each cow’s brand, he determined a rather silly statistic: For each cow in line, he knows the number of cows that precede that cow in line that do, in fact, have smaller brands than that cow.

Given this data, tell FJ the exact ordering of the cows.

Input

  • Line 1: A single integer, N

  • Lines 2…N: These N-1 lines describe the number of cows that precede a given cow in line and have brands smaller than that cow. Of course, no cows precede the first cow in line, so she is not listed. Line 2 of the input describes the number of preceding cows whose brands are smaller than the cow in slot #2; line 3 describes the number of preceding cows whose brands are smaller than the cow in slot #3; and so on.

Output

  • Lines 1…N: Each of the N lines of output tells the brand of a cow in line. Line #1 of the output tells the brand of the first cow in line; line 2 tells the brand of the second cow; and so on.
    Sample Input
    5
    1
    2
    1
    0

Sample Output

2
4
5
3
1

题目大意

先输入一个n
然后再给n个正整数A(i)~A(i+n),数字A(i)表示有A(i)个数字比当前数字小
根据这个信息求出原数字串

解题思路

创建线段树,每个节点记录的是当前节点代表的范围内有几个数字
从后遍历给的信息
对于最后一个数字来说,比较的范围是前1~n-1个数字
比如给出的A(n)是0,说明前面的数字都要比最后一个数字大,那么最后一个数字就是1,因为没有比它更小的正整数了,可以看出A(i)代表的就是当前范围内第A(i)+1个数,所有的数只能出现一次,当某一数被拿出时要标记已访问

代码

#include"iostream"
#include"cmath"
#include"cstdio"
using namespace std;
int pre[10000],tree[41000];
void build(int n,int left){
	for(int i=left;i<left+n;i++){//线段树最底层第一个元素的下标是left,把n个元素都初始化为1
		tree[i]=1;
	}
	while(left!=1){
		for(int i=left/2;i<left;i++){
			tree[i]=tree[i<<1]+tree[(i<<1)+1];//向上更新,每个节点都是当前子树包含的数字个数
		}
		left/=2;
	}
} 
int find(int rt,int rank,int left){//找当前范围内第rank个数
	tree[rt]--;//有一个数要被取出,从上向下更新线段树节点的状态
	if(tree[rt]==0&&rt>=left)return rt;//找到那个数了,递归出口
	if(tree[rt<<1]<rank)return find((rt<<1)+1,rank-tree[rt<<1],left);//如果左子树数的个数不够就递归右子树
	if(tree[rt<<1]>=rank)return find((rt<<1),rank,left);//左子树数的数量够就递归左子树
}
int ans[10000];//存储原数字串
int main(){
	int n;cin>>n;
	int left=1<<(int (log(n)/log(2))+1);//线段树底层最左边的元素下标求法
	build(n,left);
	for(int i=1;i<n;i++){
		scanf("%d",&pre[i]);
	}
	for(int i=n-1;i>=0;i--){
		ans[i]=find(1,pre[i]+1,left)-left+1;//要减去left再加1,就是正确答案
	}
	for(int i=0;i<n;i++){
		printf("%d\n",ans[i]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值