SP227 ORDERS - Ordering the Soldiers
ORDERS - Ordering the Soldiers
大意
对于每组测试数据,给出 \(n\) 个士兵(刚开始是有序的),然后给出 \(n\) 个数,表示每个士兵 \(i\) 向前走了 \(a_i\) 步。最后输出士兵忘记了怎么排之后的队列。
思路
分析一下可以得出, \(i\) 号士兵就是要站在前 \(i-1\) 个士兵排完之后的第 \(a_{i+1}\) 个空位。我们可以维护一个前缀和,表示这个位置前有 \(a_i\) 个空位。所以我们只需要看第一个 \(c_j\ge a_i\) 的 \(j\) 就可以了。
优化
简单推理可知 \(c\) 序列是单调递减的,所以可以用二分来优化。前缀和也可以用树状数组来优化。这样时间复杂度就降低到了 \(O(t\times n \times \log{n})\)。
code:
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2,3,"Ofast","inline")
#define int long long
#define double long double
#define endl '\n'
const int N=200001;
int T,n,a[N],c[N],ans[N];
bool cmp(int x,int y){return a[x]<a[y];}
int lowbit(int x){return (x&-x);}
void add(int x,int d){
while(x<=n){
c[x]+=d;
x+=lowbit(x);
}
}
int cha(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
int find(int x){
int l=1,r=n,mid;
while(l<r){
mid=(l+r)/2;
if(cha(mid)>=x) r=mid;
else l=mid+1;
}
return r;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("","r",stdin);
// freopen("","w",stdout);
//↑以上为初始化 ↑
//------------------------------
cin >> T;//多测!
while(T--){
memset(c,0,sizeof(c));
cin >> n;
for(int i = 1;i<=n;i++) cin >> a[i],add(i,1);
for(int i = n;i>=1;i--){
ans[i]=find(i-a[i]);
add(ans[i],-1);
}
for(int i = 1;i<=n;i++) cout << ans[i] << ' ';
cout << endl;
}
return 0;
}

浙公网安备 33010602011771号