1. 程式人生 > >Poj(2182)——Lost Cows(線段樹)

Poj(2182)——Lost Cows(線段樹)

Description

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. 最近學了一下線段樹,把基本題目都做了一下,但是一直都沒有時間來總結一下,所以現在抽空總結了一下。 這道題的題意大致是: 有N頭奶牛,編號為1~N,亂序排成一列,現在已知每頭牛前面有多少頭牛比它的編號小,求排隊後從前往後數,每頭牛的編號。 注意因為第一頭牛前面肯定只有0頭牛比它的編號小,那麼題目這裡沒有給出,所以我們要自己加上去。 一開始沒想到要怎麼用線段樹,看了一下題解後,然後懂了。 首先我們從後往前掃描,然後遇到數字a,就說明它是原先剩餘序列中第a+1個數,找到該編號後刪除,然後繼續重複上述的操作。那麼哪裡用到了線段樹呢?找的過程要用到線段樹,看一個區間內未被刪除的數字個數能否滿足使當前要找的數成為第a+1個,能則遞迴左子樹,否則遞迴右子樹,那麼葉子節點的值就是其初始編號。
#include<stdio.h>
#include<string.h>
#define maxn 10000
int small[maxn],ans[maxn];	//ans是用來儲存結果的;  
struct node{
	int lc,rc,len;
}s[4*maxn];
void build(int root,int lc,int rc){
	s[root].lc=lc;
	s[root].rc=rc;
	s[root].len=rc-lc+1;
	if(lc==rc) return ;
	build(2*root,lc,(lc+rc)/2);
	build(2*root+1,(lc+rc)/2+1,rc);
}
int query(int root,int k){
	s[root].len--;
	if(s[root].lc==s[root].rc)return s[root].lc;
	else if(s[2*root].len>=k) return query(root*2,k);
	else return query(root*2+1,k-s[root*2].len);
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=2;i<=n;i++) scanf("%d",&small[i]);
	small[1]=0;
	build(1,1,n);
	for(int i=n;i>=1;i--){
		//這裡的意思是:前面有幾個比它小的,那麼它就在原來的地方排第small+1位; 
		ans[i]=query(1,small[i]+1);
	}
	for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}