线段树和树状数组各过一次POJ2182

来源:互联网 发布:python自动化运维开发 编辑:程序博客网 时间:2024/04/28 18:15

这道题和卖票那道题目差不多,都是从前往后想不好想,从后往前想可以做的。

我们假设已经知道了所有数字的排列,那么对于最大的那个数,所有的数都比他小,所以,若他前面有N个数的话,那么N+1就是他的位置,这个最大数的位置就确定了,其他所有的数都比他小,所以,统计其他数前面有几个比这个数小的数的时候,最大数绝对不会被计算在内,所以可以把最大数所在的位置变成0,这样第二大的数就变成了最大的数,以此类推。

这道题也可以用树状数组做,查询的时候使用2分就可以了。

#include<stdio.h>#include<string.h>int dat[40000];int n;void PushUp(int rt){dat[rt]=dat[rt*2]+dat[rt*2+1];}void build(int rt,int l,int r){//printf("rt:%d l:%d r:%d\n",rt,l,r);if(r-l==1){dat[rt]=1;}else{int mid=(l+r)/2;build(rt*2,l,mid);build(rt*2+1,mid,r);PushUp(rt);}}void update(int rt){}int query(int rt,int l,int r,int x){dat[rt]--;//if(a>=r||l>=b) return -1;if(r-l==1){return l;}int mid=(l+r)/2;int ls=rt*2;int rs=rt*2+1;if(x<=dat[ls]){return query(ls,l,mid,x);}elsereturn query(rs,mid,r,x-dat[ls]);}int num[20000];int ans[20000];int main(){scanf("%d",&n);build(1,1,n+1);for(int i=2;i<=n;i++){scanf("%d",&num[i]);}for(int i=n;i>=1;i--){int a=query(1,1,n+1,num[i]+1);ans[i]=a;}for(int i=1;i<=n;i++){printf("%d\n",ans[i]);}}
//树状数组+2分版
#include<stdio.h>#include<string.h>int bit[50000];int n;int sum(int x){    int s=0;    while(x)    {        s+=bit[x];        x-=(x&(-x));    }    return s;}void add(int i,int x){    while(i<=n)    {        bit[i]+=x;        i+=i&(-i);    }}int bifind(int x){    int lb=0,ub=n;    while(ub-lb>1)    {        int mid=(ub+lb)>>1;        int s=sum(mid);        if(s>=x)            ub=mid;        else            lb=mid;    }    return ub;}int num[10000];int ans[10000];int main(){    scanf("%d",&n);    for(int i=2;i<=n;i++)    {        scanf("%d",&num[i]);    }    for(int i=1;i<=n;i++)        add(i,1);    for(int i=n;i>=1;i--)    {        ans[i]=bifind(num[i]+1);        add(ans[i],-1);    }    for(int i=1;i<=n;i++)        printf("%d\n",ans[i]);}



原创粉丝点击