Portal --> loj2472

Solution

  感觉是一道很有意思的贪心题啊ovo(想了一万个假做法系列==)

  比较直观的想法是,既然一个数\(i\)只会对应一个\(\lfloor\frac{i}{k}\rfloor\),那么这个不小于关系可以建成一棵树的样子,每个节点的编号代表这个节点对应的位置,然后第\(i\)号点的父亲是\(\lfloor\frac{i}{k}\rfloor\)

  然后这个时候我们可以想到一个初步的贪心策略:注意到\(d\)的顺序并不影响结果,所以我们可以考虑将\(d\)从小到大排序之后,我们按照深度一层一层处理(假设这层的节点数量为\(x\)),先从\(d\)中没有分配的位置中取出前\(x\)个数,然后从大到小分配到这层的节点上

  但是这是一个假做法qwq只能在\(d\)互不相同的情况下保证正确性

  如果说存在相同的\(d\),那么可能会出现这种情况:

\[\begin{aligned}
d&=\{1,1,1,2\}\\
YourAns&=\{1,1,1,2\}\\
RealAns&=\{1,1,2,1\}
\end{aligned}
\]

  因为相同的值我们其实可以放到子树里面去,然后我们就可以用更大的值来填这层的点了

  这个时候注意到,我们可能需要“预留”一些值放到子树里面去,所以我们换一个角度来思考问题:我们将\(d\)从大到小排序,考虑如果我们将某一个位置\(i\)的值分配给当前节点\(x\),那么必须保证不小于\(d_i\)的数最少要有\(sz[x]\)个(其中\(sz[x]\)表示\(x\)的子树大小),因为我们已经将\(d\)排了序,所以其实相当于要保证\(i\)以及前面的还没有被分配掉的位置最少要有\(sz[x]\)个,如果说有多个相同的数,那么从贪心的角度来看肯定是要取最靠右的那个

  所以我们可以用线段树维护一个\(f\)数组,\(f[i]\)表示在\(i\)及以前的被分配掉的位置数量,那么我们按顺序给每个节点填数,每次只要找到一个\(d\)值最大的位置\(i\)满足\(i\)以前的每个位置\(j\)都满足\(j-f[j]>=sz\)即可(也就是最靠左的满足条件的那个值),然后如果说这个值有多个,把最靠右的位置分配给当前节点(记这个位置为\(x\)),并且下标为\(x\sim n\)的\(f\)值就应该对应地加上\(sz\)(因为要给当前节点的子树在前面预留位置),所以实现一个区间加和查询就好了

  这里还有一个小问题,每次我们都选择当前值最靠右的位置拿来分配,那如果说这个位置之前已经被选过一次了呢?这里其实可以理解为一个比较抽象的处理:我们可以理解为把原来在这个位置的那个点以及前面的点往前移一位(如果有空位那么前面就不用再移了),把最右边的那个位置空出来给当前点(不会出现这段值相同的位置已经全被选完了还会再选到这个值情况),所以处理的时候每次直接将最右边的那个分配出去即可

  最后还有一点就是,因为我们在处理每个节点的时候会为其子树预留位置,所以在处理到一个点的时候,应该把父亲预留的位置给去掉(但不能把父亲的位置也给去掉了,所以应该是减去\(sz[fa]-1\)的贡献)

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5*(1e5)+10,SEG=N*4;
namespace Seg{/*{{{*/
int ch[SEG][2],tag[SEG],mn[SEG];
int n,tot;
void pushup(int x){mn[x]=min(mn[ch[x][0]]+tag[ch[x][0]],mn[ch[x][1]]+tag[ch[x][1]]);}
void _build(int x,int l,int r){
tag[x]=0;
if (l==r){mn[x]=l;return;}
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
pushup(x);
}
void build(int _n){n=_n; tot=1; _build(1,1,n);}
void _update(int x,int l,int r,int lx,int rx,int delta){
if (l<=lx&&rx<=r) {tag[x]+=delta; return;}
int mid=lx+rx>>1;
if (r<=mid) _update(ch[x][0],l,r,lx,mid,delta);
else if (l>mid) _update(ch[x][1],l,r,mid+1,rx,delta);
else{
_update(ch[x][0],l,mid,lx,mid,delta);
_update(ch[x][1],mid+1,r,mid+1,rx,delta);
}
pushup(x);
}
void update(int l,int r,int delta){_update(1,l,r,1,n,delta);}
int _query(int x,int lx,int rx,int k,int tg){
tg+=tag[x];
if (lx==rx) return (mn[x]+tg)>=k?lx:lx+1;
int mid=lx+rx>>1,rval=mn[ch[x][1]]+tg+tag[ch[x][1]];
if (k<=rval) return _query(ch[x][0],lx,mid,k,tg);
else return _query(ch[x][1],mid+1,rx,k,tg);
}
int query(int k){return _query(1,1,n,k,0);}
}/*}}}*/
int d[N],ans[N],ed[N],fa[N],sz[N];
int clean[N];
int n;
double K;
bool cmp(int x,int y){return x>y;}
void prework(){
for (int i=n;i>=1;--i){
fa[i]=(int)(1.0*i/K);
ed[i]=i; ++sz[i];
sz[fa[i]]+=sz[i];
if (i!=n&&d[i]==d[i+1]) ed[i]=ed[i+1];
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%lf",&n,&K);
for (int i=1;i<=n;++i) scanf("%d",d+i);
sort(d+1,d+1+n,cmp);
Seg::build(n);
prework();
for (int i=1;i<=n;++i){
if (fa[i]&&!clean[fa[i]]){
Seg::update(ans[fa[i]],n,sz[fa[i]]-1);
clean[fa[i]]=true;
}
ans[i]=Seg::query(sz[i]);
ans[i]=ed[ans[i]];
Seg::update(ans[i],n,-sz[i]);
}
for (int i=1;i<=n;++i) printf("%d ",d[ans[i]]);
printf("\n");
}

【loj2472】IIIDX的更多相关文章

  1. 【BZOJ5249】IIIDX(贪心,线段树)

    题意: 思路:赛季结束之前余总推荐的一道好题,不愧是余总 From https://www.cnblogs.com/suika/p/8748115.html 简略的说就是在预留足够多的位置的前提下贪心 ...

  2. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  3. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  4. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  6. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  7. Python高手之路【三】python基础之函数

    基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...

  8. Python高手之路【一】初识python

    Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...

  9. 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】

    说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...

随机推荐

  1. 第四篇 前端学习之JQuery基础

    一 jQuery是什么? jQuery就是一个JavaScript的库. <1> jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入 ...

  2. Vue.js项目中,当图片无法显示时则显示默认图片

    使用require将图片进入,写法如下: data: () => ({logo: 'this.src="' + require('../assets/img.png') + '&quo ...

  3. jpa的@Query中"?"占位符的使用小坑

    今天使用@Query自定义查询语句,出现了一个错误: java.lang.IllegalArgumentException: Parameter with that position [1] did ...

  4. python分割文件目录/文件名和后缀

    import os file_path = "D:/test/test.py" (filepath,tempfilename) = os.path.split(file_path) ...

  5. RIGHT-BICEP测试第二次

    1.Right-结果是否正确? 正确 2.B-是否所有的边界条件都是正确的? 正确 3.P-是否满足性能要求? 部分满足 4.是否满足有无括号? 无 5.数字个数是否不超过十? 只是双目运算 6.能否 ...

  6. SDN前瞻 传统网络的缺陷

    引言 在网络发展速度如此之快的今天,传统网络的架构充满了危机,主要有这四个问题: 传统网络部署管理困难. 分布式架构瓶颈出现. 流量控制难真正实现. 设备不可编程. 现在的网络厂商 种类繁多的网络厂商 ...

  7. OOP 1.5 类和对象的基本概念与用法1

    1.定义 面向对象的基本特点:抽象.封装.继承.多态 面向对象程序设计方法:将某类客观事物的共同特点归纳出来,形成一个数据结构 抽象:将事物所能进行的行为归纳出来,形成一个个函数,这些函数可以用来操作 ...

  8. 使用git提交代码的一些小心得

    1.不进行push不能运行的代码,如果需要提交,可以先注释,保证其他人pull时,可以得到能够正常使用的代码 2.每做完一件事,写一条描述,一次提交.不要等写了一堆代码,然后写一堆描述,这样如果需要查 ...

  9. 解析DXF图形文件格式

    一.DXF文件格式分析 DXF文件由标题段.表段.块段.实体段和文件结束段5部分组成,其内容如下. ☆标题段(HEADER)标题段记录AutoCAD系统的所有标题变量的当前值或当前状态.标题变量记录了 ...

  10. PAT---福尔摩斯约会时间

    主要为字符串的处理,注意读懂题目意思. 设置输出域宽和填充字符的函数分别为setw(int n),setfill(char c);两个函数的头文件为#include<iomanip>; # ...