BZOJ

洛谷


求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负。

对于询问\((a,b,c,d)\),同样也可以二分中位数\(x\),然后把原序列对应地改为\(+1\)或\(-1\)。

此时区间\([b,c]\)中的数是必选的,求一个和\(sum\)。显然对于区间\([a,b-1]\),我们可以求一个和最大的后缀;对于区间\([c+1,d]\),可以求一个和最大的前缀。然后判断总和是否非负。

这些都可以建出线段树来维护。

显然每次二分不能重新建树。考虑刚开始时对每个\(x\)建一棵树。

假设序列中的数互不相同,每次二分的数从\(x\)变成\(x+1\)时,显然与\(x\)相比,从\(+1\)变成\(-1\)的数只有一个。也就是每次与上一次相比,只会改变一个位置。

如果序列中的数会重复,显然总复杂度也不会受影响。

所以可以对每个\(x\)建可持久化线段树,维护区间和、最大前缀后缀和即可。

复杂度\(O(n\log n+q\log^2n)\)。

对于重复的数(假设有\(c\)个位置满足\(A_i=x\)),其实不需要去重,建\(c\)棵不同的线段树即可。无论真正的中位数和\(x\)的关系如何,一定能二分到正确位置。

如果去重,注意对于每个值我们要保留最开始的那棵树(比如2 2 2,一直修改root[now]的话会是-1 -1 1,实际上可以是1 1 1 )。注意线段树范围是1~n不是1~cnt。。

去重虽然能优化二分边界,但是好像没什么实际效果(更慢了)= =

话说这就是可持久化线段树啊,为什么要叫它主席树呢


  1. //12848kb 756ms
  2. #include <cstdio>
  3. #include <cctype>
  4. #include <assert.h>
  5. #include <algorithm>
  6. //#define gc() getchar()
  7. #define MAXIN 50000
  8. #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
  9. typedef long long LL;
  10. const int N=20005;
  11. int root[N];
  12. std::pair<int,int> A[N];
  13. char IN[MAXIN],*SS=IN,*TT=IN;
  14. struct Segment_Tree
  15. {
  16. #define ls son[x][0]
  17. #define rs son[x][1]
  18. #define S N*19//建树还有一个2n空间,但是不要卡着开n(2+logn)= =
  19. int tot,Ans,son[S][2],sum[S],pre[S],suf[S];
  20. #undef S
  21. inline void Update(int x)
  22. {
  23. int l=ls, r=rs;
  24. sum[x]=sum[l]+sum[r];
  25. pre[x]=std::max(pre[l],sum[l]+pre[r]);
  26. suf[x]=std::max(suf[r],sum[r]+suf[l]);
  27. }
  28. void Build(int &x,int l,int r)
  29. {
  30. x=++tot;
  31. if(l==r) {sum[x]=pre[x]=suf[x]=1; return;}
  32. int m=l+r>>1;
  33. Build(ls,l,m), Build(rs,m+1,r), Update(x);
  34. }
  35. void Modify(int &x,int y,int l,int r,int p)
  36. {
  37. x=++tot;
  38. if(l==r) {sum[x]=-1; return;}
  39. int m=l+r>>1;
  40. p<=m ? (rs=son[y][1],Modify(ls,son[y][0],l,m,p)) : (ls=son[y][0],Modify(rs,son[y][1],m+1,r,p));
  41. Update(x);
  42. }
  43. int QuerySum(int x,int l,int r,int L,int R)
  44. {
  45. if(L<=l && r<=R) return sum[x];
  46. int m=l+r>>1;
  47. if(L<=m)
  48. if(m<R) return QuerySum(ls,l,m,L,R)+QuerySum(rs,m+1,r,L,R);
  49. else return QuerySum(ls,l,m,L,R);
  50. return QuerySum(rs,m+1,r,L,R);
  51. }
  52. void QueryPre(int x,int l,int r,int L,int R)
  53. {
  54. if(L<=l && r<=R)
  55. {
  56. Ans=std::max(pre[x],Ans+sum[x]);
  57. return;
  58. }
  59. int m=l+r>>1;
  60. if(m<R) QueryPre(rs,m+1,r,L,R);
  61. if(L<=m) QueryPre(ls,l,m,L,R);//max(QueryPre(lson),QuerySum(lson)+QueryPre(rson)) 这样写的复杂度是啥啊...= =
  62. }
  63. void QuerySuf(int x,int l,int r,int L,int R)
  64. {
  65. if(L<=l && r<=R)
  66. {
  67. Ans=std::max(suf[x],Ans+sum[x]);
  68. return;
  69. }
  70. int m=l+r>>1;
  71. if(L<=m) QuerySuf(ls,l,m,L,R);
  72. if(m<R) QuerySuf(rs,m+1,r,L,R);
  73. }
  74. }T;
  75. inline int read()
  76. {
  77. int now=0;register char c=gc();
  78. for(;!isdigit(c);c=gc());
  79. for(;isdigit(c);now=now*10+c-48,c=gc());
  80. return now;
  81. }
  82. bool Check(int x,int n,int a,int b,int c,int d)
  83. {
  84. int s=T.QuerySum(root[x],1,n,b,c);
  85. if(s>=0) return 1;
  86. if(a<b)
  87. {
  88. T.Ans=0, T.QuerySuf(root[x],1,n,a,b-1);//可以用同一个函数直接Query合并区间的=v= 为了常数算了= =
  89. if((s+=T.Ans)>=0) return 1;
  90. }
  91. if(c<d)
  92. {
  93. T.Ans=0, T.QueryPre(root[x],1,n,c+1,d);
  94. if((s+=T.Ans)>=0) return 1;
  95. }
  96. return 0;
  97. }
  98. int main()
  99. {
  100. static int ref[N];
  101. const int n=read();
  102. for(int i=1; i<=n; ++i) A[i]=std::make_pair(read(),i);
  103. std::sort(A+1,A+1+n); int cnt=1; ref[1]=A[1].first;
  104. for(int i=2; i<=n; ++i) if(A[i].first!=A[i-1].first) ref[++cnt]=A[i].first;
  105. T.Build(root[1],1,n), root[2]=root[1];
  106. // for(int i=2; i<=n; ++i) T.Modify(root[i],root[i-1],1,n,A[i-1].second);
  107. for(int i=2,now=2; i<=n; ++i)//A[n]不用管.
  108. {
  109. T.Modify(root[now],root[now],1,n,A[i-1].second);
  110. if(A[i].first!=A[i-1].first) ++now, root[now]=root[now-1];//root[++now]=root[now-1] 还是不要写这种语句了=-=
  111. }
  112. for(int Q=read(),ans=0,q[4]; Q--; )
  113. {
  114. q[0]=(read()+ans)%n+1, q[1]=(read()+ans)%n+1, q[2]=(read()+ans)%n+1, q[3]=(read()+ans)%n+1;
  115. std::sort(q,q+4);
  116. int l=1,r=cnt,mid;
  117. while(l<=r)
  118. if(Check(mid=l+r>>1,n,q[0],q[1],q[2],q[3])) ans=mid, l=mid+1;
  119. else r=mid-1;
  120. printf("%d\n",ans=ref[ans]);
  121. }
  122. return 0;
  123. }

BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)的更多相关文章

  1. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  2. 【BZOJ-2653】middle 可持久化线段树 + 二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discu ...

  3. [bzoj 2653][国家集训队]middle

    传送门 Description 一个长度为\(n\)的序列\(a\),设其排过序之后为\(b\),其中位数定义为\(b[n/2]\),其中\(a,b\)从\(0\)开始标号,除法取下整. 给你一个长度 ...

  4. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

  5. BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)

    题意: 左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值 思路: 对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1 ...

  6. BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)

    首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...

  7. 【bzoj2653】middle 可持久化线段树区间合并

    题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...

  8. bzoj 4504: K个串 可持久化线段树+堆

    题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...

  9. bzoj 3514: GERALD07加强版 lct+可持久化线段树

    题目大意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解: 这道题考试的时候没想出来 于是便爆炸了 结果今天下午拿出昨天准备的题表准备做题的时候 题表里就有这题 ...

随机推荐

  1. hdu4009最小树形图板子题

    /*调了一下午的最小树形图,昨天刚刚看懂模板..最小树形图,就是有向图的最小生成树,很神奇==*/ #include<iostream> #include<cstring> # ...

  2. 性能测试四十六:Linux 从网卡模拟延时和丢包的实现

    Linux 中模拟延时和丢包的实现 使用ifconfig命令查看网卡 Linux 中使用 tc 进行流量管理.具体命令的使用参考 tc 的 man 手册,这里简单记录一下使用 tc 模拟延时和丢包的命 ...

  3. sass基础—属性嵌套以及跳出嵌套 @at-root

    /*注意:定义的变量若是没有使用则不会编译到css文件中.*//*1)sass的局部变量*/$font:14px;//定义$font:12px !default; //没有default时是重新赋值, ...

  4. easyui 布局之window和panel一起使用时,拉动window宽高时panel不跟随一起变化

    项目开发中布局是每一个组件都由最外层的window和内部的至少一个panel组成,其他的细小组件再依次放到panel中. 问题:当拉动外部的window时我们希望内部的panel的宽高也跟着变化,但是 ...

  5. JAVA中的Token

    JAVA中的Token 基于Token的身份验证 来源:转载 最近在做项目开始,涉及到服务器与安卓之间的接口开发,在此开发过程中发现了安卓与一般浏览器不同,安卓在每次发送请求的时候并不会带上上一次请求 ...

  6. Appium Demo

    import unittestimport timefrom appium import webdriverfrom public import configimport os #类继承unittes ...

  7. 插件使用一表单验证一validation

    jquery-validation是一款前端经验js插件,可以验证必填字段.邮件.URL.数字范围等,在表单中应用非常广泛. 官方网站 https://jqueryvalidation.org/ 源码 ...

  8. Django认证系统auth认证

    使用Django认证系统auth认证 auth认证系统可以处理范围非常广泛的任务,且具有一套细致的密码和权限实现.对于需要与默认配置不同需求的项目,Django支持扩展和自定义认证;会将用户信息写入到 ...

  9. 封装cuda/cudnn写卷积网络前向计算程序

    目录 基本编译配置 一些常识 BN层的坑 cuda基础 向cuda核函数传入结构体指针? 参考:http://galoisplusplus.coding.me/blog/2018/05/22/cuda ...

  10. JavaScript数组去重的6个方法

    方法一无需思考,我们可以得到 O(n^2) 复杂度的解法.定义一个变量数组 res 保存结果,遍历需要去重的数组,如果该元素已经存在在 res 中了,则说明是重复的元素,如果没有,则放入 res 中. ...