Bzoj5251 线段树+贪心

记录本蒟蒻省选后的第一篇题解!
国际惯例的题面:

首先这个东西显然是一棵树。
如果我们把数值排序,并建立这棵树的dfs序,显然dfs序上的一个区间对应数值的一个区间,且根为数值区间左端点。
如果你这样想,恭喜你能获得50分,如果记得加了eps会获得55~60分。
因为当数值可以相同的时候,这个贪心是存在反例的。
考虑10个点的二叉堆,9个1一个2,显然2应该在位置6,而这样跑出来2会在位置10!
因为可能一个子树的数值是不连续的,我们可以在把根节点的位置减小为相同数值的左一个的时候,把这个区间的一个值分给别的子树。
考虑修正贪心。
我们离散化序列,记录每个值出现次数。
然后我们令f[i]表示>=i的数的个数。
先统计出子树size,考虑bfs遍历整个子树。
这样我们子树的根节点x要选择的就是满足f[1,i]均>=siz[x]的最大的i,我们令ans[x]=i。
之后我们需要让f[1,i]减去siz[x],为了给这个子树预留位置。
当然,在遍历到一个节点的时候需要把为他的父亲预留的size加回去,也就是说,让f[1,ans[fa[x]]]加上siz[fa[x]]-1。
这个线段树二分怎么实现?由于这个序列不单调,我们维护区间min,如果左区间的min>=siz[x]的话就去右区间查询。
最后特判当前的点能否选择即可。
(考试的时候想到了线段树,但是非得用dfs序列遍历,怎么也弄不对......)

注意这题BZOJ卡eps!!!!!

代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define debug cout
  6. using namespace std;
  7. const int maxn=5e5+1e2;
  8. const double eps=1e-;
  9.  
  10. int in[maxn],srt[maxn],siz[maxn],len;
  11. int ans[maxn],fa[maxn],ts[maxn],vis[maxn];
  12. int n;
  13.  
  14. struct SegmentTree {
  15. int l[maxn<<],r[maxn<<],lson[maxn<<],rson[maxn<<],lazy[maxn<<],mi[maxn<<],cnt;
  16. inline void build(int pos,int ll,int rr) {
  17. l[pos] = ll , r[pos] = rr;
  18. if( ll == rr ) return;
  19. const int mid = ( ll + rr ) >> ;
  20. build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+,rr);
  21. }
  22. inline void apply(int pos,int delta) {
  23. mi[pos] += delta , lazy[pos] += delta;
  24. }
  25. inline void push(int pos) {
  26. if( !lazy[pos] || l[pos] == r[pos] ) return;
  27. apply(lson[pos],lazy[pos]) , apply(rson[pos],lazy[pos]) , lazy[pos] = ;
  28. }
  29. inline void maintain(int pos) {
  30. if( l[pos] == r[pos] ) return;
  31. mi[pos] = min( mi[lson[pos]] , mi[rson[pos]] );
  32. }
  33. inline void update(int pos,int ll,int rr,int delta) {
  34. if( r[pos] < ll || rr < l[pos] ) return;
  35. if( ll <= l[pos] && r[pos] <= rr ) return apply(pos,delta);
  36. push(pos);
  37. update(lson[pos],ll,rr,delta) , update(rson[pos],ll,rr,delta);
  38. maintain(pos);
  39. }
  40. inline int query(int pos,int lim) {
  41. if( l[pos] == r[pos] ) return mi[pos] >= lim ? l[pos] : l[pos] - ;
  42. push(pos);
  43. if( mi[lson[pos]] >= lim ) return query(rson[pos],lim);
  44. else return query(lson[pos],lim);
  45. }
  46. }segt;
  47.  
  48. inline void getseq() {
  49. sort(in+,in++n);
  50. srt[len=] = in[] , siz[] = ;
  51. for(int i=;i<=n;i++) {
  52. if( in[i] != in[i-] ) srt[++len] = in[i];
  53. ++siz[len];
  54. }
  55. segt.build(segt.cnt=,,len);
  56. for(int i=;i<=len;i++) segt.update(,,i,siz[i]);
  57. }
  58.  
  59. inline void calcpoint(int x) {
  60. if( fa[x] && !vis[fa[x]] ) segt.update(,,ans[fa[x]],ts[fa[x]]-) , vis[fa[x]] = ;
  61. int fd = segt.query(,ts[x]); ans[x] = fd;
  62. segt.update(,,fd,-ts[x]);
  63. }
  64.  
  65. int main() {
  66. static double k;
  67. scanf("%d%lf",&n,&k);
  68. for(int i=;i<=n;i++) scanf("%d",in+i) , fa[i] = (int) ( (double) i / k + eps ) , ts[i] = ;
  69. getseq();
  70. for(int i=n;i;i--) if( fa[i] ) ts[fa[i]] += ts[i];
  71. for(int i=;i<=n;i++) calcpoint(i);
  72. for(int i=;i<=n;i++) printf("%d%c",srt[ans[i]],i!=n?' ':'\n');
  73. return ;
  74. }

Bzoj5251 线段树+贪心的更多相关文章

  1. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  2. 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)

    传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码

  3. codeforces 675E Trains and Statistic 线段树+贪心统计

    分析:这个题刚看起来无从下手 但是我们可以先简化问题,首先可以固定起点i,求出i+1到n的最小距离 它可以到达的范围是[i+1,a[i]],贪心的想,我们希望换一次车可以到达的距离尽量远 即:找一个k ...

  4. BZOJ1805[Ioi2007]Sail船帆——线段树+贪心

    题目描述 让我们来建造一艘新的海盗船.船上有 N个旗杆,每根旗杆被分成单位长度的小节.旗杆的长度等于它被分成的小节的数目.每根旗杆上会挂一些帆,每张帆正好占据旗杆上的一个小节.在一根旗杆上的帆可以任意 ...

  5. BZOJ5249 九省联考2018IIIDX(线段树+贪心)

    显然这形成了一个树形结构.考虑这样一种贪心:按照曲目顺序,每次取消其父亲的预留,并选择当前可选择(保证其子树有合法选择且满足预留)的最大值,然后对其子树预留出大于等于他的一些值.这个做法显然是正确的. ...

  6. BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)

    题意 题目链接 Sol 不难发现题目给出的是一个树,其中\(\frac{i}{K}\)是\(i\)的父亲节点 首先,当\(d_i\)互不相同时,一个显然的贪心策略就是优先给编号小的分配较大的权值.可以 ...

  7. [九省联考2018] IIIDX 线段树+贪心

    题目: 给出 k 和 n 个数,构造一个序列使得 d[i]>=d[i/k] ,并且字典序最大. 分析: 听说,当年省选的时候,这道题挡住了大批的高手,看上去十分简单,实际上那道弯段时间内是转不过 ...

  8. 【Luogu】P1607庙会班车Fair Shuttle(线段树+贪心)

    我不会做贪心题啊……贪心题啊……题啊……啊…… 我真TM菜爆了啊…… 这题就像凌乱的yyy一样,把终点排序,终点相同的按起点排序.然后维护一个查询最大值的线段树.对于一个区间[l,r],如果这个区间已 ...

  9. bzoj 2811: [Apio2012]Guard【线段树+贪心】

    关于没有忍者的区间用线段树判就好啦 然后把剩下的区间改一改:l/r数组表示最左/最右没被删的点,然后删掉修改后的左边大于右边的:l升r降排个序,把包含完整区间的区间删掉: 然后设f/g数组表示i前/后 ...

随机推荐

  1. PowerDesigner使用64位JDK连接MYSQL填坑记.md

    你在这座城市,做过最孤独的事是什么? 曾经试过销声匿迹,最终只是无人问及! 系统环境 利用powerdesigner反向生成表结构时报: ** connection test failed** 胖先 ...

  2. 在CentOS上导出JVM内存信息

    首先看下Tomcat的进程Id: [root@iZ25Z ~]# ps aux | grep java www 2111 4.0 23.5 1637648 452756 ? Sl 10:12 4:35 ...

  3. 用phpStorm的数据库工具来管理你的数据库

    phpStorm是一个功能强大的IDE,不仅对PHP提供了支持,而且对前端HTML.CSS.JavaScript的支持也是非常不错的.此外,phpStorm还集成了很多实用的功能,下面就phpStor ...

  4. Export SQLite data to Excel in iOS programmatically(OC)

    //For the app I have that did this, the SQLite data was fairly large. Therefore, I used a background ...

  5. 利用overflow-x实现横向滚动的xiaoguo

    在进行app开发中经常遇到横向滚动的效果,相信很多人都是用js写的吧,其实用css的overflow-x也可以写出啦哦~~~ (1)介绍overflow-x: 1)浏览器支持 所有主流浏览器都支持 o ...

  6. centos7.2 安装 composer

    安装Composer https://pkg.phpcomposer.com/#how-to-install-composer  # 下载composer.phar curl -sS https:// ...

  7. 2017/05/21 java 基础 随笔

    工具类:所有的方法都是静态的,如果一个类中所有的方法都是静态的,需要再多做一步,私有构造方法,不让其他类创建本类对象. 生成文档: java.lang 包不用导入 常见代码块的应用    * a:局部 ...

  8. linux中使用corntab和shell脚本自动备份nginx日志,按天备份

    编写shell脚本,实现nginx日志每天自动备份到指定文件夹! 需要的命令mv , corntab -e(定时任务),shell脚本 这里先说一下corntab: https://www.cnblo ...

  9. Linux驱动技术(五) _设备阻塞/非阻塞读写【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6377925.html 等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节 ...

  10. C#中的GetElementsByClassName方法

    2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24     public static class Spread     {    ...