【loj2472】IIIDX
Solution
感觉是一道很有意思的贪心题啊ovo(想了一万个假做法系列==)
比较直观的想法是,既然一个数\(i\)只会对应一个\(\lfloor\frac{i}{k}\rfloor\),那么这个不小于关系可以建成一棵树的样子,每个节点的编号代表这个节点对应的位置,然后第\(i\)号点的父亲是\(\lfloor\frac{i}{k}\rfloor\)
然后这个时候我们可以想到一个初步的贪心策略:注意到\(d\)的顺序并不影响结果,所以我们可以考虑将\(d\)从小到大排序之后,我们按照深度一层一层处理(假设这层的节点数量为\(x\)),先从\(d\)中没有分配的位置中取出前\(x\)个数,然后从大到小分配到这层的节点上
但是这是一个假做法qwq只能在\(d\)互不相同的情况下保证正确性
如果说存在相同的\(d\),那么可能会出现这种情况:
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的更多相关文章
- 【BZOJ5249】IIIDX(贪心,线段树)
题意: 思路:赛季结束之前余总推荐的一道好题,不愧是余总 From https://www.cnblogs.com/suika/p/8748115.html 简略的说就是在预留足够多的位置的前提下贪心 ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
- Python高手之路【一】初识python
Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...
- 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】
说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...
随机推荐
- Power Designer逆向工程导入Oracle表,转为模型加注释
1.打开PowerDesigner ——文件——Reverse Engineer——DataBase 2.选择所要连接数据库版本,此处使用的是oracle version 11g. 3.点击红色区域, ...
- 原生WebGL场景中绘制多个圆锥圆柱
前几天解决了原生WebGL开发中的一个问题,就是在一个场景中绘制多个几何网格特征不同的模型,比如本文所做的绘制多个圆锥和圆柱在同一个场景中,今天抽空把解决的办法记录下来,同时也附上代码.首先声明,圆柱 ...
- Lua学习笔记(8): 元表
元表 Lua中提供了元表(Metatable),其实这个元表就比较像面向对象中的类了,可以通过给某些特殊的标识符赋值达到重载的效果,这些特殊的标识符有: 名称 功能 __index 元表的索引方法 _ ...
- Literature Books
Lean In (Sheryl Sandberg) Option B (Sheryl Sandberg) Ready Player One
- 算法笔记(c++)--回文
算法笔记(c++)--回文 #include<iostream> #include<algorithm> #include<vector> using namesp ...
- Phonegap 环境配置
目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...
- 吴恩达机器学习笔记——正规方程(Normal Equation)
问题描述:m examples : (x(1),y(1)), (x(2),y(2)),..., (x(m),y(m)) and n features; 计算方法:θ = (XTX)-1XTy; 计算过 ...
- erlang节点互相ping,一个能ping通,另外一个不行。
今天发现一个问题,2个erlang节点,1个主动ping另外一个不通,然后等待另外一个ping过来,2个节点才连通.记录一下. 首先,erlang节点的cookie是一致的.查了文档,cookie一致 ...
- String、StringBuilder与StringBuffer的区别
1.String类是public.final修饰的. 在Java中,被final修饰的类是不允许被继承的,并且String它的成员方法都默认为final方法. 查看源码得知,String类其实是通过c ...
- JS高级 2
递归:函数自己调用自己 在JavaScript中唯一能产生作用域的东西是 函数!js中只有函数可以创建作用域 词法作用域,也叫做静态作用域 //就是在代码写好的那一刻,变量和函数的作用域就已经确定了, ...