BZOJ传送门
洛谷传送门
解析:
首先我们有一个很显然的 错误 的贪心,按照字典序和siz依次将最大的
s
i
z
siz
siz个权值分配给以某个点为根的子树,然后根节点选择最小的权值后递归处理。
很遗憾,它只能处理所有 d d d不同的情况。
比如这组数据:
4 3.0
1 1 2 2
答案应该是:
1 2 2 1
然而贪心是:
1 1 2 2
考虑为什么会出现这种情况,这时候,贪心的结果出来 1 1 1和 2 2 2的值是相等的,然而这个相等的值其实可以传给后面 1 1 1的子树,这样 2 2 2就有机会得到更大的值。
所以我们需要处理一下贪心。
小的尽可能向后丢。
所以我们可以先排个序,处理出目前未分配的权值中和当前权值相等的有哪些。
然后需要查找目前所有可以直接分配权值(即所有祖先权值已经确定)的点中,后面有至少 c n t cnt cnt个的第一个。
后缀和。。。
所以线段树维护当前可决策的点标号,算出后缀和后在树上二分找到每个就行了。
当然,由于维护的只有后缀和,所以可以直接树状数组,顺便学习了一下树状数组上的二分写法。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline double getdb(){
re char c;
while(!isdigit(c=gc()));re double x=c^48;
while(isdigit(c=gc()))x=x*10+(c^48);
if(c^'.')return x;
re double y=1.0;
while(isdigit(c=gc()))x+=(y/=10)*(c^48);
return x;
}
cs int Rlen=5e6+5;
char obuf[Rlen],*p=obuf;
inline void put_char(char c){*p++=c;}
struct io{~io(){fwrite(obuf,1,p-obuf,stdout);}}out;
inline void outint(int a){
static char ch[23],top;
if(a==0)pc('0');
while(a)ch[++top]=a-a/10*10,a/=10;
while(top)pc(ch[top--]^48);
}
}
using namespace IO;
cs int N=5e5+5;
int s[1<<19|1],r;
inline void add(int pos,int val){
for(int re i=pos;i<=r;i+=i&-i)s[i]+=val;
}
inline int find(int val){
val=s[r]-val;
int res=r,tmp=0,d=r>>1;
for(;d;d>>=1)s[res]>val?res-=d:(tmp=res,val-=s[res],res|=d);
return s[res]>val?tmp:res;
}
int n;double k;
int d[N],son[N],fa[N],siz[N],cnt[N],ans[N];
signed main(){
n=getint();k=getdb();
for(r=1;r<n;r<<=1);
for(int re i=1;i<=n;++i)son[fa[i]=i/k]=i,d[i]=getint();
sort(d+1,d+n+1);
for(int re i=n;i;--i)siz[fa[i]]+=++siz[i],cnt[i]=d[i]==d[i+1]?cnt[i+1]+1:1;
for(int re i=1;i<=son[0];++i)add(i,siz[i]);
for(int re i=1;i<=n;++i){
int pos=find(cnt[i])+1;
ans[pos]=d[i];
add(pos,-siz[pos]);
for(int re ch=son[pos-1]+1;ch<=son[pos];++ch)
add(ch,siz[ch]);
}
for(int re i=1;i<=n;++i)outint(ans[i]),pc(' ');
return 0;
}