[Usaco2003 Open]Lost Cows

Description

N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judg
ment, they visited the neighborhood 'watering hole' and drank a few too many beers before dinner. Wh
en it was time to line up for their evening meal, they did not line up in the required ascending num
erical 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 s
illy 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 c
ows.
1~n,乱序排列,告诉每个位置的前面的数字中比它小的数的个数,求每个位置的数字是多少 

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 i
n slot #2; line 3 describes the number of preceding cows whose brands are smaller than the cow in sl
ot #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 

解题思路:

这个题目意思很明了(因为只有一句话)。。。

看到这个题我们会有这样的一个思路(用样例举个例子,其中a[i]为读入的它前面有几个比它小的数):


首先我们从后往前确定各个位置上的值(自己好好领会一下,大概意思就是如果从前往后,前面的值可能还要被修改一次);

step 1:因为在剩下的未填入的数字:1 2 3 4 5中1是最小的

因此:


step 2 :

因为在剩下的未填入的数字:2 3 4 5中3是第二小的

因此:


step 3:...

step 4 : ...

step 5 : ...

最后就可以得出样例了。。。

这样看来我们似乎可以用线段树单点操作来解决。。

接着就是代码了(附有较详细注释):

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=8000;
int n;
int a[maxn],tree[4*maxn+10];//tree数组里存的是剩下的数 
//在这里我偷了一个懒,a数组先是读入的值,后来也被用来存答案 
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void build(int k,int l,int r)
{
    if(l==r){tree[k]=1;return ;}//当走到最末尾的叶子节点的时候,它只有自己一个节点,所以是1 
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k]=tree[k<<1]+tree[k<<1|1];
}
void find(int k,int l,int r,int wz)
{
    if(!tree[k])return ;//没有点了当然就退出 
    tree[k]--;//因为要从这一段中取走一个数,自然要-1 
    if(l==r){a[wz]=l;return ;}//保存答案 
    int mid=(l+r)>>1;
    if(tree[k<<1]>a[wz])find(k<<1,l,mid,wz);//如果当前要取的第a[wz]小的数比左儿子小,自然是访问左儿子 
    else//否则访问右儿子 
    {
        a[wz]-=tree[k<<1];//将左儿子的数的个数减去
		//因为我要接着访问右儿子,当然要将左儿子的个数减去
		//实在不理解的话自己手推2遍find函数 
        find(k<<1|1,mid+1,r,wz);
    }
    tree[k]=tree[k<<1]+tree[k<<1|1];
}
int main()//主函数就不讲了。。。 
{
    n=read();
    build(1,1,n);
    for(int i=2;i<=n;i++)
        a[i]=read();
    for(int i=n;i>=1;i--)
        find(1,1,n,i);
    for(int i=1;i<=n;i++)
        printf("%d\n",a[i]);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值