题意:你知道有一个1~n的排列,但具体排列你不知道。现在给出1~n每个前缀的逆序数对数,让你还原这个排列。
思路:从最后一个值开始考虑,rev[i]-rev[i-1]表示前面比它大的数的个数,我们就可以得出当前位置的数字在1-n中的次序,然后进行权值线段树的操作~~~
ac代码
#include <iostream> #include<stdio.h> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack> #include<queue> #include<set> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define Max(a,b) a=max(a,b) #define Min(a,b) a=min(a,b) const int inf=0x3f3f3f3f; #define siz 50005 int n,rev[siz],tr[siz*4],ans[siz]; void init() { memset(tr,0,sizeof(tr)); } void PushUp(int u) { tr[u]=tr[u<<1]+tr[u<<1|1]; } void build(int u,int l,int r) { if(l==r){tr[u]=1;return;} int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); PushUp(u); } int query(int u,int l,int r,int ord) { if(l==r){tr[u]-=1;return l;} int mid=(l+r)>>1; int ret=0; if(tr[u<<1]>=ord)ret=query(u<<1,l,mid,ord); else ret=query(u<<1|1,mid+1,r,ord-tr[u<<1]); PushUp(u); return ret; } int main() { std::ios::sync_with_stdio(false); int T; scanf("%d",&T); while(T--){ scanf("%d",&n); init(); for(int i=1;i<=n;i++)scanf("%d",&rev[i]); build(1,1,n); for(int i=n;i>=1;i--){ ans[i]=query(1,1,n,i-rev[i]+rev[i-1]); } printf("%d",ans[1]);for(int i=2;i<=n;i++)printf(" %d",ans[i]); printf(" "); } return 0; }