题意:
原题给的背景太繁琐,直接简化一下;
给定一个序列 $A$ , 其中 $A[i]$ 表示 $i$ 之前有多少个比当前数大,现在求原序列,序列值为 $1...n$;
思路:
倒序还原,查询当前未使用的数字中的 第 $k$ 大 是多少,用树状数组维护当前值是否被使用,二分查询 第 $k$ 大 ,复杂度 $O( n logn log n)$。
1 /* 2 * Author: windystreet 3 * Date : 2018-08-11 12:50:35 4 * Motto : Think twice, code once. 5 */ 6 #include<bits/stdc++.h> 7 8 using namespace std; 9 10 #define X first 11 #define Y second 12 #define eps 1e-5 13 #define gcd __gcd 14 #define pb push_back 15 #define PI acos(-1.0) 16 #define lowbit(x) (x)&(-x) 17 #define bug printf("!!!!! "); 18 #define mem(x,y) memset(x,y,sizeof(x)) 19 20 typedef long long LL; 21 typedef long double LD; 22 typedef pair<int,int> pii; 23 typedef unsigned long long uLL; 24 25 const int maxn = 2e5+7; 26 const int INF = 1<<30; 27 const int mod = 1e9+7; 28 struct node 29 { 30 int v,id; 31 }s[maxn]; 32 int tree[maxn]; 33 int vis[maxn]; 34 int n; 35 void init(){ 36 for(int i=0;i<=n;i++) 37 tree[i] = 0,vis[i] = 0; 38 return; 39 } 40 41 void add(int x,int v){ 42 for(int i=x;i<=n;i+=lowbit(i)) 43 tree[i] += v; 44 return ; 45 } 46 47 int query(int x ){ 48 int res = 0; 49 for(int i=x ;i;i-=lowbit(i)) 50 res += tree[i]; 51 return res; 52 } 53 54 void solve(){ 55 scanf("%d",&n); 56 init(); 57 for(int i=1;i<=n;i++){ 58 scanf("%d",&s[i].v); 59 add(i,1); // 将每一个数字表示为存在 60 } 61 for(int i=n;i>=1;i--){ 62 int x = i - s[i].v; // k 63 int L = 1,R = n; 64 while(L <= R){ // 二分查找 65 int mid = (L+R)>>1; // 若当前的值大于等于k则记录答案 66 if(query(mid)>=x)s[i].id = mid,R = mid-1; 67 else L = mid + 1; 68 } 69 add(s[i].id,-1); // 使用了之后就取消标记 70 } 71 for(int i=1;i<=n;i++){ 72 printf("%d%c",s[i].id," "[i==n]); 73 } 74 return; 75 } 76 77 int main() 78 { 79 // freopen("in.txt","r",stdin); 80 // freopen("out.txt","w",stdout); 81 // ios::sync_with_stdio(false); 82 int t = 1; 83 scanf("%d",&t); 84 while(t--){ 85 // printf("Case %d: ",cas++); 86 solve(); 87 } 88 return 0; 89 }