又一次对自己的智商产生了怀疑。。这道题虽然用N方的循环也能水过但是刚学过线段树还是自己用线段树做一遍吧~~
看着题解做的。。因为实在想不到线段树该怎么处理。。
等我学完专题一定发誓从此不再看题解。。嘤嘤。。被自己蠢哭了。。。
题目大意:一群有编号的牛乱序排成一列,已知每头牛之前的编号小于自己的牛的个数,要求按顺序输出这列牛的编号。。
思路:使用一个线段树维护全部牛编号的排序,可以求出当前第K大的编号,node中的len属性是计数自己下属剩余编号的个数,每查询一次自减一次,叶子节点len==0表示已被使用,由于查询子树时会与子树剩余结点数相比较,并且查询右子树时会用K减去左子树的剩余结点数,所以len=0相当于节点被删除。巧妙高效的实现了删除操作。
#include<stdio.h>
#include<iostream>
#include<math.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define MAX_N 8005
struct node
{
int l;
int r;
int len;
}tree[MAX_N<<2]; //tree的第0位不使用
int source[MAX_N];
int ans[MAX_N];
void build(int l,int r,int dex)
{
tree[dex].l=l;
tree[dex].r=r;
tree[dex].len=r-l+1;
if(l==r) return;
build(l,(l+r)/2,dex<<1);
build((l+r)/2+1,r,(dex<<1)+1);
return;
}
int query(int dex,int sum)
{
tree[dex].len--; //当len==0时,相当于该节点被删除
if(tree[dex].l==tree[dex].r)
return tree[dex].l;
if(sum<=tree[dex<<1].len) //与左子树剩余结点数相比较
return query(dex<<1,sum);
if(sum>tree[dex<<1].len)
return query((dex<<1)+1,sum-tree[dex<<1].len);
}
int main()
{
int n;
scanf("%d",&n);
source[1]=0;
for(int i=2;i<=n;i++)
scanf("%d",&source[i]);
build(1,n,1);
for(int i=n;i>=1;i--)
ans[i]=query(1,source[i]+1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}