poj 2182
题意:给出编号1~n的奶牛,是乱序的并且给出了每一个奶牛前小于自己序号的奶牛数目。输出奶牛的正确位置。
假设第i个奶牛的高度(就是指前面的小于自己序号的奶牛的数目)为Ai。因此第n个奶牛的序号必然是Ai+1。然后我们将这个奶牛砍掉,那么第n-1个奶牛就可以根据它的高度和已经判断出的第n个奶牛来确定。推出一般的情况:我们用Ck来保存1~k中确定的奶牛数(也就是我们砍掉的奶牛),因此还没有砍的奶牛数为(k-Ck);在倒序处理的过程中, 对于奶牛j,其高度为Aj+1,我们只要找出这样的k就行了:Aj+1==k-Ck。
k-Ck代表了什么意思呢?其实就是在排好序的奶牛序列中,把已经确定的牛砍去之后k的高度。
Ck我们用树状数组来维护,k的查找我们可以用二分查找来优化。
#include<cstdio> #include<iostream> using namespace std; #define MAX 80020 int ok[MAX],sum[MAX],cow[MAX]; int lowbit(int i) { return i & (-i); } int update(int i,int n) { while(i<=n) { sum[i]++; i+=lowbit(i); } return 0; } int GetSum(int i) { int s=0; while(i) { s+=sum[i]; i-=lowbit(i); } return s; } int search(int k,int n) { int left=1,right=n,mid,temp; while(left<right) { mid=(left+right)>>1; temp=mid-GetSum(mid); if(temp<k) left=mid+1; else right=mid; } return left; } int main() { int i,n; while(scanf("%d",&n)!=EOF) { memset(sum,0,sizeof(sum)); memset(ok,0,sizeof(ok)); for(i=2;i<=n;i++) scanf("%d",&cow[i]); for(i=n;i>0;i--) { int k=search(cow[i]+1,n); update(k,n); ok[i]=k; } for(i=1;i<=n;i++) printf("%d\n",ok[i]); } return 0; }