【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 ————————— ...
随机推荐
- Jmeter如何做接口测试
最近在学习Jmeter,记录下来,与大家分享. 1. 打开Jmeter,我用的是5.0版本,打开后如下图所示: 2. 右键测试计划,添加 - 线程(用户) - 线程组,如下如图所示: 3. 右键线程组 ...
- P,V操作及同步互斥实例
无论是计算机考研.计算机软件水平考试.计算机操作系统期末考试还是其他计算机岗位考试,P.V原语操作都是一个常考点.下面笔者总结了关于P.V操作的一些知识. 信号量是最早出现的用来解决进程同步与互斥问题 ...
- python数据可视化——matplotlib 用户手册入门:使用指南
参考matplotlib官方指南: https://matplotlib.org/tutorials/introductory/usage.html#sphx-glr-tutorials-introd ...
- XSS 注入检查点
如果你有个论坛,一般你会很注意用户发帖的注入问题,往往这个地方不会被注入,因为开发特别照顾.原则上XSS都是用户输入的,但是许多边角还是容易忽略.枚举一些检查点. 分页 分页通用组件获取url,修改p ...
- Live Archive 训练题
7091 Height Ordering Mrs. Chambers always has her class line up in height order (shortest at the fro ...
- High School: Become Human(数学思维)
Year 2118. Androids are in mass production for decades now, and they do all the work for humans. But ...
- Divide by three, multiply by two(DFS+思维)
Polycarp likes to play with numbers. He takes some integer number x, writes it down on the board, an ...
- 20172332『Java程序设计』课程结对编程练习_四则运算第二周阶段总结
20172313『Java程序设计』课程结对编程练习_四则运算第二周阶段总结 小组成员 20172326康皓越 20172313余坤澎 20172332于欣月 小组编程照片 设计思路 设计一个生成符号 ...
- 软工实践 - 第三十次作业 Beta答辩总结
福大软工 · 第十二次作业 - Beta答辩总结 组长本次博客作业链接 项目宣传视频链接 本组成员 1 . 队长:白晨曦 031602101 2 . 队员:蔡子阳 031602102 3 . 队员:陈 ...
- 解决:Invalid character found in the request target.The valid characters are defined in RFC 7230 and RFC3986
目录 背景 原因分析 处理方法 参考 背景 在将tomcat升级到7.0.81版后,发现系统的有些功能不能使用了,查询日志发现是有些地址直接被tomcat认为存在不合法字符,返回HTTP 400错误响 ...