题目链接:https://cn.vjudge.net/problem/CodeForces-1208D
题解:从后往前操作,这样就能通过si确定出pi是什么,当然不能枚举,线段树维护下当前每个数如果放在当前位置的话si是多少,然后就是线段树的基本操作了,区间更新点查询
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
struct node {
int l, r;
ll val, laz;
}tree[N << 2];
int n;
ll a[N];
int pos[N];
void build(int l, int r, int cur) {
tree[cur].l = l;
tree[cur].r = r;
tree[cur].laz = 0;
if(l == r) {
tree[cur].val = 1LL * (l - 1) * l / 2;
return;
}
int mid = (l + r) >> 1;
build(l, mid, cur << 1);
build(mid + 1, r, cur << 1 | 1);
tree[cur].val = max(tree[cur << 1].val , tree[cur << 1 | 1].val);
}
void pushdown(int cur) {
if(tree[cur ].laz) {
tree[cur << 1].laz += tree[cur].laz;
tree[cur << 1 | 1].laz += tree[cur].laz;
tree[cur << 1].val += tree[cur].laz;
tree[cur << 1 | 1].val += tree[cur].laz;
tree[cur].laz = 0;
}
}
void update(int pl, int pr, int cur, ll val) {
if(pl <= tree[cur].l && tree[cur].r <= pr) {
tree[cur].val += val;
tree[cur].laz += val;
return;
}
pushdown(cur);
if(pl <= tree[cur << 1].r) update(pl, pr, cur << 1, val);
if(pr >= tree[cur << 1 | 1].l) update(pl, pr, cur << 1 | 1, val);
tree[cur].val = max(tree[cur << 1].val, tree[cur << 1 | 1].val);
}
int query(int cur, ll val) {
// cout << tree[cur].l << " " << tree[cur].r << " " << tree[cur].val << endl;
if(tree[cur].l == tree[cur].r) return tree[cur].l;
pushdown(cur);
if(tree[cur << 1].val >= val) return query(cur << 1, val);
else return query(cur << 1 | 1, val);
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
build(1, n, 1);
for(int i = n; i >= 1; i--) {
pos[i] = query(1, a[i]);
if(pos[i] < n) update(pos[i] + 1, n, 1, -pos[i]);
update(pos[i], pos[i], 1, -100000000000);
}
for(int i = 1; i <= n; i++)
printf("%d%c", pos[i], " \n"[i == n]);
return 0;
}