题解:首先我们需要建立一个权值线段树,节点的权值分别是1~n,然后我就只需要逆序遍历si数组,找到大于s[i] + 1的数,这个数就是当前位置的值。注意的是,如果我们找到了那个数,就要将那个位置的权值赋为0,表示该数已经用过了。
#include#include using namespace std;const int maxn = 2e5+7;typedef long long ll;ll s[maxn], ans[maxn], tree[maxn << 2];void update(int root, int l, int r, int pos, ll val) { if(l == r) { tree[root]= val; return; } int mid = (l + r) >> 1; if(pos <= mid) { update(root << 1, l, mid, pos, val); } else { update(root << 1 | 1, mid + 1, r, pos, val); } tree[root] = tree[root << 1] + tree[root << 1 | 1];}int query(int root, int l, int r, ll val) { if(l == r) { return tree[root]; } int mid = (l + r) >> 1; if(tree[root << 1] >= val) { return query(root << 1, l, mid, val); } else { return query(root << 1 | 1, mid + 1, r, val - tree[root << 1]); }}int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%I64d", &s[i]); update(1, 1, n, i, i * 1LL); //建立一颗权值线段树 } for(int i = n; i >= 1; i--) { ans[i] = query(1, 1, n, s[i] + 1LL); //找到大于si + 1的这个数 update(1, 1, n, ans[i], 0LL); //权值赋0 } for(int i = 1; i <= n; i++) { printf("%I64d ", ans[i]); } return 0; }