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;
}
posted @ 2026-10-22 07:29  elon_giao  阅读(4)  评论(0)    收藏  举报