https://www.lydsy.com/JudgeOnline/problem.php?id=5249
把树建出来
如果所有的d互不相同,后续遍历即可
现在有的d相同
将d从小到大排序,考虑如何将这n个数填进树里
相当与为x的子树预订d序列中的一段
而且当且这个d填的位置越靠后越好
CTSC试机现场发题解,真爽。。。
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 500001 int d[N],ans[N]; int siz[N]; int front[N],nxt[N],to[N],tot; int sum[N<<2]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; siz[u]+=siz[v]; } void change(int k,int l,int r,int pos,int w) { if(l==r) { sum[k]+=w; return; } int mid=l+r>>1; if(pos<=mid) change(k<<1,l,mid,pos,w); else change(k<<1|1,mid+1,r,pos,w); sum[k]=sum[k<<1]+sum[k<<1|1]; } int find(int k,int l,int r,int s) { if(l==r) return l; int mid=l+r>>1; if(s<=sum[k<<1|1]) return find(k<<1|1,mid+1,r,s); return find(k<<1,l,mid,s-sum[k<<1|1]); } int main() { int n; double k; read(n); scanf("%lf",&k); for(int i=1;i<=n;++i) read(d[i]); sort(d+1,d+n+1); for(int i=1;i<=n;++i) siz[i]=1; for(int i=n;i;--i) add(i/k,i); for(int i=front[0];i;i=nxt[i]) change(1,1,n,to[i],siz[to[i]]); int j=1,t; for(int i=1;i<=n;i=j) { while(j<=n && d[i]==d[j]) j++; for(int l=j-i;l;--l) { t=find(1,1,n,l); ans[t]=d[i]; change(1,1,n,t,-siz[t]); for(int h=front[t];h;h=nxt[h]) change(1,1,n,to[h],siz[to[h]]); } } for(int i=1;i<=n;++i) printf("%d ",ans[i]); return 0; }