题意:有一个n个整数的序列,给出每个数前面比这个数小的数的个数。求原序列。
思路:从后往前,用树状数组保存每个数是否出现过。如果出现过就是1,没有出现过就是0。假设题目给出的序列是A[]。那么,对于A[i],第i个位置上的数,应当满足在树状数组中,第i个位置前面0的个数正好等于A[i],这个数就是所求的这个位置的值。
代码如下:
需要注意的是,每次二分找到的l或者r还有mid,都必须是前面没有出现过,即是9。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=8005;
int C[maxn];
int rec[maxn];
int ans[maxn];
bool have[maxn];
int n;
int lowbit(int x)
{
return x&-x;
}
void update(int x)
{
while(x<=n){
C[x]++;
x+=lowbit(x);
}
}
int query(int x)
{
int ret=0;
while(x>0){
ret+=C[x];
x-=lowbit(x);
}
return ret;
}
int getl(int l)
{
while(have[l]){
l++;
}
return l;
}
int getr(int r){
while(have[r]){
r--;
}
return r;
}
int getmid(int mid)
{
while(have[mid]){
mid++;
}
return mid;
}
int main()
{
// freopen("data.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<=n+2;++i){
C[i]=0;
have[i]=false;
}
rec[0]=0;
for(int i=1;i<n;++i){
scanf("%d",&rec[i]);
}
for(int i=n-1;i>=0;--i){
int r=getr(n);
int l=getl(1);
while(l<r){
int mid=(l+r)>>1;
int tmp=query(mid);
if(mid-tmp-(have[mid]?0:1)<rec[i])l=getl(mid+1);
else if(mid-tmp-(have[mid]?0:1)>rec[i]) r=getr(mid-1);
else {
l=getmid(mid);
r=getmid(mid);
}
}
ans[i]=l;
update(l);
have[l]=1;
}
for(int i=0;i<n;++i){
printf("%d\n",ans[i]);
}
return 0;
}
线段树版本的代码,没用到二分:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int seg[30005];
int cow[80005];
int ans[8005];
int query(int o,int l,int r,int sum)
{
if(l==r)return l;
int mid=l+(r-l)/2;
int lr=(mid-l+1)-seg[o*2];
if((mid-l+1)-seg[o*2]>sum &&
(mid-l+1)-seg[o*2]>=1)return query(o*2,l,mid,sum);
else return query(o*2+1,mid+1,r,sum-lr);
}
int p,v;
void update(int o,int l,int r)
{
int mid=l+(r-l)/2;
if(l==r)seg[o]+=v;
else{
if(p<=mid){
update(o*2,l,mid);
}else{
update(o*2+1,mid+1,r);
}
seg[o]=seg[o*2]+seg[o*2+1];
}
}
int main()
{
// freopen("data.txt","r",stdin);
int n;
scanf("%d",&n);
cow[1]=0;
for(int i=2;i<=n;++i){
scanf("%d",&cow[i]);
}
memset(seg,0,sizeof(seg));
for(int i=n;i>=1;--i){
int pos=query(1,1,n,cow[i]);
p=pos;
v=1;
update(1,1,n);
ans[i-1]=pos;
}
for(int i=0;i<n;++i){
printf("%d\n",ans[i]);
}
return 0;
}