【题解】

  一眼可以想到一个类似二叉树后序遍历的贪心做法,然而这个做法在有相同数字的情况下是错误的。最简单的反例就是n=4,d={1,1,1,2},正解是1,1,2,1,而贪心是1,1,1,2. 所以这个贪心被叉掉了。

  我们先把d从大到小排序,然后我们用f[i]表示第i个位置之前(包括i位置)还能取的数的个数。第一个节点显然去第size[1]大的数字就好,如果有多个相等的,那么就取最右边的,因为这可以为后面的节点预留更大的数。当取好一个点的值之后,需要给它的子树预留数字;我们并不能确定子树中的每个节点分别取什么值,但是我们知道子树取的数字一定大于当前节点的数值,所以子树取的值一定在当前节点的数字前面。我们只需要把当前位置及其右边的f[i]减去size即可。每次需要确定一个节点i的取值时,我们只需要找到最大的数值val满足val所在位置右边的c[j]都大于size[i],如果有多个相等的val,我们还是取最右边的那个。要找到这样的val,我们在线段树上二分就可以了。

  需要注意的是,在计算到某个父亲的第一个孩子时,我们需要把父亲预留的位置加回来。

  

 #include<cstdio>
#include<algorithm>
#define N 500010
#define rg register
#define ls (u<<1)
#define rs (u<<1|1)
using namespace std;
int n,m,d[N],siz[N],pos[N],cnt[N];
double k;
struct tree{
int l,r,del,mn;
}a[N<<];
inline int read(){
int k=,f=; char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(''<=c&&c<='')k=k*+c-'',c=getchar();
return k*f;
}
inline int min(int x,int y){return x<y?x:y;}
inline bool cmp(int x,int y){return x>y;}
void build(int u,int l,int r){
a[u].l=l; a[u].r=r; int mid=(l+r)>>;
if(l<r) build(ls,l,mid),build(rs,mid+,r),a[u].mn=min(a[ls].mn,a[rs].mn);
else a[u].mn=l;
}
inline void pushdown(int u){
int d=a[u].del; a[u].del=;
a[ls].del+=d; a[rs].del+=d;
a[ls].mn+=d; a[rs].mn+=d;
}
void update(int u,int l,int d){
if(l<=a[u].l){
a[u].mn+=d; a[u].del+=d; return;
}
if(a[u].del) pushdown(u);
update(rs,l,d);
if(l<=((a[u].l+a[u].r)>>)) update(ls,l,d);
a[u].mn=min(a[ls].mn,a[rs].mn);
}
int find(int u,int l,int r,int v) {
if (l==r) {
if (a[u].mn>=v) return l; return l+;
}
if (a[u].del) pushdown(u);
int mid=(l+r)>>;
if (a[rs].mn>=v) return find(ls,l,mid,v);
return find(rs,mid+,r,v);
}
int fa(int x) {return x/k;}
int main(){
n=read(); scanf("%lf",&k); build(,,n);
for(rg int i=;i<=n;i++) d[i]=read();
sort(d+,d++n,cmp);
for(rg int i=n-;i;i--) if(d[i]==d[i+]) cnt[i]=cnt[i+]+;
for(rg int i=n;i;i--) siz[fa(i)]+=++siz[i];
for(rg int i=;i<=n;i++){
if(fa(i)&&fa(i)!=fa(i-)) update(,pos[fa(i)],siz[fa(i)]-);
pos[i]=find(,,n,siz[i]); pos[i]+=cnt[pos[i]]; pos[i]-=cnt[pos[i]]++;
update(,pos[i],-siz[i]);
}
for(rg int i=;i<=n;i++) printf("%d ",d[pos[i]]);
return ;
}

最新文章

  1. 手把手教你玩GDB
  2. ThinkPHP 分页类的使用及退出功能的实现
  3. 视频 之自定义VideoView
  4. js 正则
  5. OC基础-day04
  6. POJ_3143 验证“歌德巴赫猜想”
  7. mybatis0208 缓存
  8. 黑马程序猿_Java 代理机制学习总结
  9. Xshell不能连接SSH的解决
  10. nodejs全局安装与本地安装区别
  11. 跨域资源共享CORS详解
  12. [LeetCode] 动态规划入门题目
  13. 003-单例OR工厂模式
  14. 20172306 2018-2019 《Java程序设计与数据结构》第一周学习总结
  15. Redis中取得所有Key、过期时间配置与获取、Key过期通知。
  16. JavaScript高级 面向对象(11)--对象的动态特性-关联数组用法
  17. .net 获取邮箱邮件列表和内容
  18. [Linux]ssh相关问题
  19. Date()函数的用法
  20. 在使用hibernate注解的时候,想对double类型的字段进行精度约束

热门文章

  1. 51Nod 1522 上下序列 —— 区间DP
  2. libnids TCP数据流重组,显示TCP连接过程的程序总无法捕获数据包解决办法:
  3. Line: 220 - com/opensymphony/xwork2/spring/SpringObjectFactory.java:220:-1
  4. SpringBoot中使用spring-data-jpa 数据库操作(下)
  5. Kettle 连接 oracle 报错:could not be found, make sure the &#39;Oracle&#39; driver (jar file) is installed.
  6. [Swift通天遁地]一、超级工具-(7)创建一个图文并茂的笔记本程序
  7. 【转】@Controller和@RestController的区别
  8. golang——database/sql包学习
  9. CF379F New Year Tree
  10. python批量下载图片