题意
有n头牛,每头牛都有一个编号。从排在第二只牛开始,给出这头牛的左边有几只编号比他小的牛。求每一个位置上牛的编号。
题意半天才看懂。。
思路
最后一只牛的编号是可以确定的。如果左边有k头编号比他小的牛,他的编号必为k+1。当最后一头牛的编号确定以后,倒数第二头牛的编号也能确定。所以我们可以倒着访问。
用sum记录所在空间剩余的位置。对于插入在 val 位置的牛他前边一定要有 val -1(1~n 建树)个剩余位置。(0~n 建树则为 val 个剩余位置)
访问结点时,如果左子树的剩余位置大于或等于 val 就访问左子树(sum[rt<<1] >= val ),否则就访问右子树。访问右子树时需要用 val 减去左子树的剩余位置( val -sum[rt<<1] ),即整个线段树的第 val 个空位(空叶子结点),也是在右儿子那的第 val -sum[rt<<1]个空位。
这道题和Buy Tickets POJ - 2828 类似
#include<cstdio>
const int maxn=1e5;
int sum[maxn<<2],p[maxn<<2],ans[maxn];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=1;
return ;
}
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
pushup(rt);
}
void update(int val,int pos,int l,int r,int rt)
{
if(l==r)
{
sum[rt]--;
ans[pos]=l;
return ;
}
int m=(l+r)>>1;
if(val<=sum[rt<<1])
update(val,pos,l,m,rt<<1);
else
update(val-sum[rt<<1],pos,m+1,r,rt<<1|1);
pushup(rt);
}
int main()
{
int n;
scanf("%d",&n);
bulid(1,n,1);
p[1]=0;
for(int i=2;i<=n;i++)
scanf("%d",&p[i]);
for(int i=n;i>0;i--)
update(p[i]+1,i,1,n,1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}
昨天刚做过一道方法一样的题,今天却想了半天才想到,还是作完题没有认真总结