链接
https://vjudge.net/problem/UVA-11525
题解
写几个就会发现
给定的
s
s
s就对应了每个位置上的数字,后面有多少个比他小的
那么我就从左往右一次填,每次找现在还存在的数字中第
s
+
1
s+1
s+1大的就好
这个过程用线段树实现,和主席树做区间
k
k
k大是一样的
代码
#include <bits/stdc++.h>
#define maxn 50010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
struct segtree
{
segtree *lch, *rch;
ll cnt, l, r;
}pool[maxn<<2], *root;
ll N, ndtot, K;
void build(segtree *p, ll l, ll r)
{
ll mid(l+r>>1);
p->l=l, p->r=r;
if(l==r)
{
p->cnt=1;
return;
}
build(p->lch=pool+ ++ndtot,l,mid);
build(p->rch=pool+ ++ndtot,mid+1,r);
p->cnt=r-l+1;
}
ll find(segtree *p, ll x)
{
ll mid(p->l+p->r>>1);
if(p->l==p->r)return p->l;
if(x>p->lch->cnt)return find(p->rch,x - p->lch->cnt);
else return find(p->lch,x);
}
void erase(segtree *p, ll pos)
{
ll mid(p->l+p->r>>1);
p->cnt--;
if(p->l==p->r)return;
if(pos<=mid)erase(p->lch,pos);
else erase(p->rch,pos);
}
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
int main()
{
auto T=read();
while(T--)
{
auto K=read();
ndtot=0;
build(root=pool+ ++ndtot,1,K);
for(auto i=1;i<=K;i++)
{
auto s=read();
auto x=find(root,s+1);
printf("%lld",x);
putchar(i==K?10:32);
erase(root,x);
}
}
}