题目链接
题目大意
有一个序列a长度为n,a中1-n每个数只出现一次,给出一个序列b,b【i】代表序列a位置之前比a【i】小的所有数之和,让你还原序列a
解题思路
当前数应该填在最后一个0的位置,后面的数都应该减去当前的数字
注意long long
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=2e5+5;
const long long inf=1e18;
long long a[N],ans[N];
struct node
{
int l,r;
long long lazy;
long long v;
};
node e[N*5];
void build(int root,int l,int r)
{
e[root].l=l;
e[root].r=r;
e[root].lazy=e[root].v=0;
if(l==r)
{
e[root].v=a[l];
return ;
}
build(root*2,l,(l+r)/2);
build(root*2+1,(l+r)/2+1,r);
e[root].v=min(e[root*2].v,e[root*2+1].v);
}
void updown(int root)
{
if(e[root].lazy)
{
e[root*2].lazy+=e[root].lazy;
e[root*2+1].lazy+=e[root].lazy;
e[root*2].v-=e[root].lazy;
e[root*2+1].v-=e[root].lazy;
e[root].lazy=0;
}
}
int que(int root,int x)
{
if(e[root].l==e[root].r)
return e[root].l;
//int mid=(e[root].l+e[root].r)/2;
updown(root);
if(e[root*2+1].v==x)
return que(root*2+1,x);
else
return que(root*2,x);
}
void update1(int root,int x)
{
if(e[root].l==e[root].r)
{
e[root].v=inf;
return ;
}
//updown(root);
int mid=(e[root].l+e[root].r)/2;
if(x<=mid)
update1(root*2,x);
else
update1(root*2+1,x);
e[root].v=min(e[root*2].v,e[root*2+1].v);
}
void update2(int root,int l,int r,int x)
{
//printf("%d %d %d %d\n",e[root].l,e[root].r,l,r);
if(e[root].l==l&&e[root].r==r)
{
e[root].v-=x;
e[root].lazy+=x;
return ;
}
updown(root);
int mid=(e[root].l+e[root].r)/2;
if(l>mid)
update2(root*2+1,l,r,x);
else
{
if(r<=mid)
update2(root*2,l,r,x);
else
{
update2(root*2,l,mid,x);
update2(root*2+1,mid+1,r,x);
}
}
e[root].v=min(e[root*2].v,e[root*2+1].v);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1;i<=n;i++)
{
int k=que(1,0);
// printf("%d\n",k);
ans[k]=i;
update1(1,k);
if(k!=n)
update2(1,k+1,n,i);
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
printf("\n");
return 0;
}