题目:点击打开链接
题解:点击打开链接
关键:处理相同的数。给每个子树预留位置,再按点标号一次处理。
每次贪心尽量选最大,在线段树上二分
注意:先离散化,且不用去重(重复的数不影响,区间减的时候都会减掉)
1-n的顺序从小到大,而不是从大到小
#include<bits/stdc++.h>
using namespace std;
#define maxn 500020
#define ls(x) (x << 1)
#define rs(x) ((x << 1) ^ 1)
#define mid(l,r) ((l + r) >> 1)
struct node{
int next,to;
}e[maxn * 2];
int head[maxn],cnt,vis[maxn],fa[maxn],id[maxn],sz[maxn];
int a[maxn],b[maxn],n,tot;
int num[maxn],add[maxn << 2],mn[maxn << 2];
double k;
inline void adde(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
inline void update(int x){
mn[x] = min(mn[ls(x)],mn[rs(x)]);
}
void build(int x,int l,int r){
if ( l == r ){ mn[x] = num[l]; return; }
build(ls(x),l,mid(l,r));
build(rs(x),mid(l,r) + 1,r);
update(x);
}
void init(){
for (int i = n ; i >= 1 ; i--){
int x = floor((double)i / k);
sz[i]++;
if ( x ) fa[i] = x , adde(x,i) , sz[x] += sz[i];
}
sort(b + 1,b + n + 1);
for (int i = 1 ; i <= n ; i++) a[i] = lower_bound(b + 1,b + n + 1,a[i]) - b , num[a[i]]++;
for (int i = n ; i >= 1 ; i--) num[i] += num[i + 1];
build(1,1,n);
}
inline void Add(int x,int d){
add[x] += d , mn[x] += d;
}
inline void pushdown(int x){
if ( add[x] ){
Add(ls(x),add[x]) , Add(rs(x),add[x]);
add[x] = 0;
}
}
void modify(int x,int l,int r,int ls,int rs,int d){
if ( ls <= l && rs >= r ){ Add(x,d); return; }
pushdown(x);
register int mid = (l + r) >> 1;
if ( ls <= mid ) modify(ls(x),l,mid,ls,rs,d);
if ( rs > mid ) modify(rs(x),mid + 1,r,ls,rs,d);
update(x);
}
int query(int x,int l,int r,int sz){
if ( l == r ) return mn[x] >= sz ? l : l - 1;
pushdown(x);
if ( sz <= mn[ls(x)] ) return query(rs(x),mid(l,r) + 1,r,sz);
return query(ls(x),l,mid(l,r),sz);
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d %lf",&n,&k);
for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]) , b[i] = a[i];
init();
for (int i = 1 ; i <= n ; i++){
if ( fa[i] ) modify(1,1,n,1,id[fa[i]],sz[i]);
id[i] = query(1,1,n,sz[i]);
modify(1,1,n,1,id[i],-sz[i]);
}
for (int i = 1 ; i <= n ; i++) printf("%d ",b[id[i]]);
printf("\n");
return 0;
}