Description:
不想讲。
Solution:
和
bzoj4010
b
z
o
j
4010
一样的想法,每次把较小的数尽量往后放。
权值线段树维护当前子树大小,然后每次求出每个权值应该放的地方,再修改即可。
理解的不是很好,需要再次思考。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 5e5 + 5;
int n;
double k;
int sum[maxn * 4], a[maxn], sz[maxn], fa[maxn], ans[maxn];
vector<int> G[maxn];
void update(int l, int r, int x, int p, int d) {
sum[x] += d;
if(l == r) {
return;
}
int mid = (l + r) >> 1;
if(p <= mid) {
update(l, mid, x << 1, p, d);
} else {
update(mid + 1, r, x << 1 | 1, p, d);
}
}
int query(int l, int r, int x, int k) {
if(l == r) {
return l;
}
int mid = (l + r) >> 1;
if(sum[x << 1 | 1] < k) {
return query(l, mid, x << 1, k - sum[x << 1 | 1]);
} else {
return query(mid + 1, r, x << 1 | 1, k);
}
}
int main() {
scanf("%d%lf", &n, &k);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
fa[i] = (int)floor(i / k);
sz[i] = 1;
G[(int)floor(i / k)].push_back(i);
}
sort(a + 1, a + n + 1);
for(int i = n; i; --i) {
sz[fa[i]] += sz[i];
}
for(int i = 0; i < G[0].size(); ++i) {
int v = G[0][i];
update(1, n, 1, v, sz[v]);
}
for(int i = 1, last = 1; i <= n; i = last) {
while(last <= n && a[i] == a[last]) {
++last;
}
for(int j = last - i; j; --j) {
int t = query(1, n, 1, j);
ans[t] = a[i];
update(1, n, 1, t, -sz[t]);
for(int k = 0; k < G[t].size(); ++k) {
update(1, n, 1, G[t][k], sz[G[t][k]]);
}
}
}
for(int i = 1; i <= n; ++i) {
printf("%d ", ans[i]);
}
return 0;
}