poj 2182 树状数组(给牛排序)

题意:有n头牛从1-n标号。现在给出n-1个数,表示第i头牛前面比它序号小的牛的个数。根据此还原牛的原始排序。

思路:从最后向前扫面序列。每次对于未确定的最后一个数来说是可以根据它前面有多少数字比它小以及之前确定的数字(在它后面的数字)而确定它是几的。二分查找当前位置填几,设这个数字为a,应满足树状数组求和结果sum(a),即后面已经填好的比a小的个数,加上f[i],即前面比a小的个数,等于a-1。猜大了则结果大于a-1,猜小了则小于。找到后把树状数组第a位标1。时间复杂度为O((logn)^2 * n)。二分的地方还是不明白。(参考http://www.cnblogs.com/rainydays/archive/2011/06/04/2072849.html)

#include <stdio.h>
#include <string.h>
#define N 8005
int a[N],tree[N],res[N];
int n;
int lowbit(int x){
	return x&(-x);
}
void add(int x){
	int i;
	for(i = x;i<=n;i+=lowbit(i))
		tree[i] ++;
}
int sum(int x){
	int i,res=0;
	for(i = x;i>0;i-=lowbit(i))
		res += tree[i];
	return res;
}
int bisearch(int x){
	int low,high,mid,temp;
	low = 1,high = n;
	while(low < high){
		mid = (low+high)>>1;
		temp = sum(mid) + x;
		if(temp <= mid)
			high = mid;
		else
			low = mid+1;
	}
	return low;
}
int main(){
	freopen("a.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		int i,j;
		memset(tree,0,sizeof(tree));
		memset(a,0,sizeof(a));
		for(i = 1;i<n;i++)
			scanf("%d",&a[i]);
		for(i = n-1;i>=0;i--){
			j = bisearch(a[i]+1);
			res[i] = j;
			add(j);
		}
		for(i = 0;i<n;i++)
			printf("%d\n",res[i]);
	}
	return 0;
}


你可能感兴趣的:(poj 2182 树状数组(给牛排序))