题目分析:
其实就是找1~n的原序列,
题目提供长为n的序列,每个元素代表这个数在原序列中其前面有多少个小于它的元素。
AC代码:
暴力解法:
//#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=8009;
int ans[N];
int xy[N];
int va[N];
int main(){
int n;
cin>>n;
xy[1]=0;//oj这个直接就不输入,,,,从2开始输入
va[1]=1;
for(int i=2;i<=n;i++){
cin>>xy[i];
va[i]=i;
}
for(int i=n;i>0;i--){
int pos=xy[i]; //从后往前找,直接找前面有几个小于它的,找到后记为-1
for(int j=1;j<=n;j++){
if(va[j]==-1){
continue;
}
if(pos==0){
ans[i]=j;
va[j]=-1;
break;
}
pos--;
}
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<endl;
}
return 0;
}
线段树解法:
//使用结构体
//#include<bits/stdc++.h>
#include<iostream>
using namespace std;
const int N=10000;
struct node{
int l;
int r;
int len;
};
struct node tree[4*N];
int pre[N],ans[N];//使用的是闭区间
void Buildtree(int left,int right,int u){//建树
tree[u].l=left;
tree[u].r=right;
tree[u].len=right-left+1;
if(left==right){
return ;
}
Buildtree(left,(left+right)>>1,u<<1);//递归左子树
Buildtree(((left+right)>>1)+1,right,(u<<1)+1);//递归右子树
}
int query(int u,int num){
tree[u].len--;//长度--
if(tree[u].l==tree[u].r){
return tree[u].l;
}
if(tree[(u<<1)].len<num){//左区间的不够,则查右区间的
return query((u<<1)+1,num-tree[u<<1].len);
}else{
return query(u<<1,num);
}
}
int main(){
int n,i;
scanf("%d",&n);
pre[1]=0;
for(int i=2;i<=n;i++){
scanf("%d",&pre[i]);
}
Buildtree(1,n,1);
for(int i=n;i>=1;i--){
ans[i]=query(1,pre[i]+1);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<endl;
}
return 0;
}
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=10000;
int pre[N],tree[4*N],ans[N];
void Buildtree(int n,int last_left){
int i;
for(i=last_left;i<last_left+n;i++){
tree[i]=1;
}
while(last_left!=1){//上面的赋值
for(i=last_left/2;i<last_left;i++){//每一层赋值
tree[i]=tree[i*2]+tree[i*2+1];
}
last_left/=2;
}
}
int query(int u,int num,int last_left){
tree[u]--;
if(tree[u]==0&&u>=last_left){
return u;
}
if(tree[u<<1]<num){
return query((u<<1)+1,num-tree[u<<1],last_left);
}else{
return query(u<<1,num,last_left);
}
}
int main(){
int n;
scanf("%d",&n);
pre[1]=0;
int last_left=1<<(int(log(n)/log(2))+1);//最后一层存放数字 ,记录最后一行第一个数的下标
for(int i=2;i<=n;i++){
scanf("%d",&pre[i]);
}
Buildtree(n,last_left);
// //
// cout<<tree[1]<<endl;
for(int i=n;i>=1;i--){
ans[i]=query(1,pre[i]+1,last_left)-last_left+1;
}
for(int i=1;i<=n;i++){
printf("%d\n",ans[i]);
}
return 0;
}
参考来源:算法竞赛从入门到进阶-罗