pku2182: Lost Cows

pku2182: http://poj.org/problem?id=2182

题意:给出n个数(1~n),接下来第2~n行输出n-1个数,第i个数num[i]表示原序列的第i个位置的数ans[i]前面的数中比他小的个数,求原序列。

解法:线段树:先建树,用tot标记该线段中未确定的数的个数,用len表示线段长度,按所给的num从后往前推

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=8010;
struct abc
{
    int l,r,len,tot;
}v[3*maxn];
int ans[maxn],num[maxn];
void build(int s,int t,int i)    //建树
{
    v[i].l=s;
    v[i].r=t;
    v[i].len=t-s+1;
    v[i].tot=v[i].len;           //一开始时所有数都未确定位置,所以tot=len
    if(s==t)
        return;
    int mid=(s+t)/2;
    build(s,mid,i*2);
    build(mid+1,t,i*2+1);
}
int find(int i,int p)           
{
    if(v[i].l==v[i].r)          
    {
        v[i].tot=0;              //此时已找到终点,返回该点的数字,因为该数位置此时确定了,所以tot=0
        return v[i].l;
    }
    int position;
    if(v[i*2].tot>=p)                //表示在左子树
        position=find(i*2,p);
    else                             //否则在右子树
        position=find(i*2+1,p-v[i*2].tot);          //减去左子树的tot
    v[i].tot=v[i*2].tot+v[i*2+1].tot;             //从下往上更新
    return position;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=2;i<=n;i++)
            scanf("%d",&num[i]);
        build(1,n,1);
        for(int i=n;i>=1;i--)              //注意num[1]未赋值,默认为0,求第一个数ans[1]时在其前面的数的个数为0
            ans[i]=find(1,num[i]+1);
        for(int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
}
/*input:
5
1
2
1
0
output:
2
4
5
3
1*/

 

 

posted on 2012-08-12 23:01  acmer-jun  阅读(176)  评论(0编辑  收藏  举报

导航