解析
感觉不至于黑的题。
然而我并不会做
d i d_i di 互不相同的时候直接无脑贪心即可,这样55分的好成绩就到手了。(交完发现可以骗到60)
滚榜级的良心分了属于是。
考虑有相同时如何做。
先把值降序排序,然后维护一棵线段树,存储每个点左侧还空余的位置。
按照 bfs序 枚举节点(其实就是1-n),每次找到空余位置不少于 s i z siz siz 的位置。
当有相等时选择占用最靠右的一个,这里我使用了离散化后堆存储下标来实现,感觉非常优美。
确定位置后位置之后的空余都要减去子树大小。
注意到,由于前面没有修改,我们实际上寻找的应该是满足后缀最小值不小于 s i z siz siz 的最左位置。
维护一个最小值,线段树二分即可实现。
记得算儿子的时候把父亲子树的影响删去。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK
")
using namespace std;
const int N=5e5+100;
const int mod=998244353;
const int C=26;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
int mn[N<<2],laz[N<<2];
inline void pushup(int k){
mn[k]=min(mn[ls],mn[rs]);
return;
}
inline void add(int k,int w){
mn[k]+=w;laz[k]+=w;
}
inline void pushdown(int k){
int o=laz[k];laz[k]=0;
if(!o) return;
add(ls,o);add(rs,o);
}
void build(int k,int l,int r){
if(l==r){
mn[k]=l;return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k);
}
int find(int k,int l,int r,int w){
if(l==r){
return mn[k]>=w?l:0;
}
pushdown(k);
if(mn[rs]<w) return find(rs,mid+1,r,w);
else{
int d=find(ls,l,mid,w);
return d?d:mid+1;
}
}
void change(int k,int l,int r,int x,int y,int w){
if(x<=l&&r<=y){
add(k,w);return;
}
pushdown(k);
if(x<=mid) change(ls,l,mid,x,y,w);
if(y>mid) change(rs,mid+1,r,x,y,w);
pushup(k);
}
int d[N];
double k;
int fa[N],siz[N];
vector<int>v[N];
int w[N];
priority_queue<int>id[N];
bool jd[N];
int q[N],cnt;
bool cmp(int x,int y){
return x>y;
}
int pl[N];
signed main(){
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
scanf("%d %lf",&n,&k);
for(int i=1;i<=n;i++) q[i]=d[i]=read();
cnt=n;
sort(q+1,q+1+cnt);
cnt=unique(q+1,q+1+cnt)-q-1;
sort(d+1,d+1+n,cmp);
for(int i=1;i<=n;i++){
d[i]=lower_bound(q+1,q+1+cnt,d[i])-q;
id[d[i]].push(i);
//printf("i=%d d=%d
",i,d[i]);
}
for(int i=n;i>=1;i--){
siz[i]++;
fa[i]=floor(i/k);
siz[fa[i]]+=siz[i];
}
build(1,1,n);
for(int i=1;i<=n;i++){
int f=fa[i];
if(f&&!jd[f]){
jd[f]=1;
change(1,1,n,pl[f],n,siz[f]-1);
}
int o=find(1,1,n,siz[i]);
pl[i]=id[d[o]].top();
//printf("i=%d fa=%d siz=%d find=%d pl=%d
",i,fa[i],siz[i],o,pl[i]);
id[d[o]].pop();
w[i]=q[d[pl[i]]];
change(1,1,n,pl[i],n,-siz[i]);
}
for(int i=1;i<=n;i++) printf("%d ",q[d[pl[i]]]);
return 0;
}
/*
8 3.000
31 15 2 54 97 65 46 61
*/