题目链接
题意:
给你一个序列
s:
s代表的是p[i]
前小于p[i]
的数组加起来的和,比如3 2 1
的s:0 0 0
题解:
我们每次一定可以确定的是最后一位的数,因为最后一位前面一定有所有小于它的数,所以我们可以确定最后一位的数,我们确定最后一位后,把他从数组中删去,然后在在接下来的数组中求最后一位的值,因为是最后一位对前面的值并不造成影响所以二分查找答案即可
AC代码:
#include<cstdio>
using namespace std;
//树状数组+二分
#define ll long long
const int maxn=2e5+5;
ll c[maxn],s[maxn],p[maxn],n;
ll lowbit(ll x)
{
return x&(-x);
}
void update(ll i,ll w)
{
while(i<=n)
{
c[i]+=w;
i+=lowbit(i);
}
}
ll getsum(ll i)
{
ll res=0;
while(i>0)
{
res+=c[i];
i-=lowbit(i);
}
return res;
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&s[i]);
update(i,i);
}
for(ll i=n;i>=1;i--)
{
ll l=1,r=n,ans;
while(l<=r)
{
ll mid=l+r>>1;
if(getsum(mid-1)<=s[i])
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
p[i]=ans;
update(ans,-ans);
}
for(ll i=1;i<=n;i++)
{
if(i!=n)
{
printf("%lld ",p[i]);
}
else
{
printf("%lld\n",p[i]);
}
}
}