poj2182 Lost Cows

题意:

对于样例

5
1
2
1
0
意思是有5个数,然后第一个0省略,实质的序列是0 1 2 1 0

要求输出的序列为res[1] res[2] res[3] res[4] res[5] 那么,对于res[2]来说,他前面有1个比他小的,对于res[3]来说,他前面有2个比他小的,对于res[4]来说,他前面有1个比他小的,对于res[5]来说,他前面有0个比他小的,这5个数为1 2 3 4 5

要求输出res序列

我的做法:

对于1 2 3 4 5建立树状数组,并且全部放入树状数组中,

此时树状数组的C数组为1 2 1 4 1

对于 0 1 2 1 0从右往左扫

比如扫到第一个0,利用树状数组二分查找找到1 2 3 4 5中从左往右的第一个数为1,那么将1从树状数组中删去,并记录结果

代码如下:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
#define MAX 8010
int a[MAX];
int c[MAX];
int res[MAX];
int lowbit(int x)
{
	return x&(-1*x);
}
void updata(int x)
{
	while(x<=n)
	{
		c[x]++;
		x+=lowbit(x);
	}
}
void dele(int x)
{
	while(x<=n)
	{
		c[x]--;
		x+=lowbit(x);
	}
}
int getsum(int x)
{
	int ans=0;
	while(x>=1)
	{
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
int Find(int x)
{
	int l=1,r=n;
	while(l<=r)//利用树状数组的getsum进行二分查找
	{
		int mid=(l+r)>>1;
		if(getsum(mid)<x)
		{
			l=mid+1;
			continue;
		}
		if(getsum(mid)>x)
		{
			r=mid-1;
			continue;
		}
		while(mid>=2&&getsum(mid)==getsum(mid-1))//保证当前的mid是仍然存在的数
		{
			mid--;
		}
		return mid;
	}
}
int main()
{
	scanf("%d",&n);
	a[1]=0;
	updata(1);
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&a[i]);
		updata(i);//依次将1 2 3...n放入树状数组中
	}
	for(int i=n;i>=1;i--)
	{
		int temp=Find(a[i]+1);//在树状数组中找到第a[i]+1个数
		res[i]=temp;//记录结果
		dele(temp);//从树状数组中删除
	}
	for(int i=1;i<=n;i++)
	{
		printf("%d\n",res[i]);//输出结果
	}
	//system("PAUSE");
	return 0;
}


你可能感兴趣的:(poj2182 Lost Cows)