题目大意:有一个序列,包含多次询问。询问区间左右端点在规定区间里移动所得到的最大中位数的值。

  考虑对于每个询问,如何得到最优区间?枚举显然是超时的,只能考虑二分。

  中位数的定义是在一个序列中,比中位数小的数跟比它大的数一样多,由于我们要求的是最大的中位数,自然希望能找到一个区间,使得该区间内比该中位数大的数尽量多。

  二分中位数k,假设比k小的数记为-1,其余的数记为1,那么我们就是要寻找最大连续子序列和,若找到的最大的和>=0,则当前的k就是合法的。

  最大连续子序列和可以用线段树来维护,由于存在多组询问,每次建一棵线段树很慢,我们选择建主席树。初始时,把数按从小到大排好序,全部的数记为1,做到第i个数时,将第i-1个数记为-1,以此做下去。

  那么这样最终二分到的答案会不会不在指定的区间范围之中呢?

  肯定是不存在的,我们可以分类讨论。

   n为偶数:n = 4时,0 1 2 3,中位数的位置为2,如果答案在1-2之间,则会有更优的答案;如果在2-3之间,显然是不可能的。

   n为奇数:n = 3时,0 1 2 3 4,中位数的位置为2,分析同上。

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <algorithm>
  4.  
  5. using namespace std;
  6.  
  7. typedef long long LL;
  8. const int maxn = ;
  9. int n, a[maxn], b[maxn], root[maxn], q[];
  10. struct Tree
  11. {
  12. int cnt;
  13. int ml[maxn*], mr[maxn*], sum[maxn*], ls[maxn*], rs[maxn*];
  14. Tree()
  15. {
  16. cnt = ;
  17. }
  18. void pushup(int rt)
  19. {
  20. ml[rt] = max(ml[ls[rt]], sum[ls[rt]]+ml[rs[rt]]);
  21. mr[rt] = max(mr[rs[rt]], sum[rs[rt]]+mr[ls[rt]]);
  22. sum[rt] = sum[ls[rt]]+sum[rs[rt]];
  23. }
  24. void build(int rt, int l, int r)
  25. {
  26. if (l == r)
  27. {
  28. ml[rt] = mr[rt] = sum[rt] = ;
  29. return ;
  30. }
  31. int mid = (l+r)>>;
  32. ls[rt] = ++cnt, build(ls[rt], l, mid);
  33. rs[rt] = ++cnt, build(rs[rt], mid+, r);
  34. pushup(rt);
  35. }
  36. void update(int las_rt, int rt, int l, int r, int p, int d)
  37. {
  38. if (l == r)
  39. {
  40. ml[rt] = mr[rt] = sum[rt] = d;
  41. return ;
  42. }
  43. int mid = (l+r)>>;
  44. if (p <= mid)
  45. {
  46. ls[rt] = ++cnt, rs[rt] = rs[las_rt];
  47. update(ls[las_rt], ls[rt], l, mid, p, d);
  48. }
  49. else
  50. {
  51. ls[rt] = ls[las_rt], rs[rt] = ++cnt;
  52. update(rs[las_rt], rs[rt], mid+, r, p, d);
  53. }
  54. pushup(rt);
  55. }
  56. int query_sum(int rt, int l, int r, int L, int R)
  57. {
  58. if (L <= l && r <= R)
  59. return sum[rt];
  60. int mid = (l+r)>>, ret = ;
  61. if (L <= mid)
  62. ret += query_sum(ls[rt], l, mid, L, R);
  63. if (R > mid)
  64. ret += query_sum(rs[rt], mid+, r, L, R);
  65. return ret;
  66. }
  67. int query_ml(int rt, int l, int r, int L, int R)
  68. {
  69. if (L <= l && r <= R)
  70. return ml[rt];
  71. int mid = (l+r)>>;
  72. if (R <= mid)
  73. return query_ml(ls[rt], l, mid, L, R);
  74. else
  75. if (L > mid)
  76. return query_ml(rs[rt], mid+, r, L, R);
  77. else
  78. return max(query_ml(ls[rt], l, mid, L, R), query_sum(ls[rt], l, mid, L, R)+query_ml(rs[rt], mid+, r, L, R));
  79. }
  80. int query_mr(int rt, int l, int r, int L, int R)
  81. {
  82. if (L <= l && r <= R)
  83. return mr[rt];
  84. int mid = (l+r)>>;
  85. if (R <= mid)
  86. return query_mr(ls[rt], l, mid, L, R);
  87. else
  88. if (L > mid)
  89. return query_mr(rs[rt], mid+, r, L, R);
  90. else
  91. return max(query_mr(rs[rt], mid+, r, L, R), query_sum(rs[rt], mid+, r, L, R)+query_mr(ls[rt], l, mid, L, R));
  92. }
  93. }T;
  94.  
  95. bool cmp(const int &AI, const int &BI)
  96. {
  97. return a[AI] < a[BI];
  98. }
  99.  
  100. void build_tree()
  101. {
  102. root[] = ++T.cnt;
  103. T.build(root[], , n);
  104. for (int i = ; i <= n; ++i)
  105. {
  106. root[i] = ++T.cnt;
  107. T.update(root[i-], root[i], , n, b[i-], -);
  108. }
  109. }
  110.  
  111. bool check(int k, int q1, int q2, int q3, int q4)
  112. {
  113. int sum = ;
  114. if (q2+ < q3)
  115. sum += T.query_sum(root[k], , n, q2+, q3-);
  116. sum += T.query_mr(root[k], , n, q1, q2);
  117. sum += T.query_ml(root[k], , n, q3, q4);
  118. return sum >= ;
  119. }
  120.  
  121. int main()
  122. {
  123. scanf("%d", &n);
  124. for (int i = ; i <= n; ++i)
  125. scanf("%d", &a[i]), b[i] = i;
  126. sort(b+, b+n+, cmp);
  127. build_tree();
  128. int ans = ;
  129. int task;
  130. scanf("%d", &task);
  131. while (task --)
  132. {
  133. scanf("%d %d %d %d", &q[], &q[], &q[], &q[]);
  134. for (int i = ; i <= ; ++i)
  135. q[i] = (q[i]+ans)%n+;
  136. sort(q+, q++);
  137. int l = , r = n;
  138. while (l < r)
  139. {
  140. int mid = (l+r+)>>;
  141. if (check(mid, q[], q[], q[], q[]))
  142. l = mid;
  143. else
  144. r = mid-;
  145. }
  146. ans = a[b[l]];
  147. printf("%d\n", ans);
  148. }
  149. return ;
  150. }

BZOJ 2653 middle 二分答案+可持久化线段树的更多相关文章

  1. bzoj 2653 二分答案+可持久化线段树

    首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和 ...

  2. BZOJ2653middle——二分答案+可持久化线段树

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

  3. bzoj 2653 middle 二分答案 主席树判定

    判断中位数是否可行需要将当前的解作为分界,大于其的置为1,小于为-1,然后b-c必选,ab,cd可不选,这个用线段树判定就好 但不能每次跑,所以套主席树,按权值排序,构建主席树,更新时将上一个节点改为 ...

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

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

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

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

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

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

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

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

  8. BZOJ 3524 [Poi2014]Couriers(可持久化线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3524 [题目大意] 给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个 ...

  9. BZOJ 3218 A + B Problem (可持久化线段树+最小割)

    做法见dalao博客 geng4512的博客, 思路就是用线段树上的结点来进行区间连边.因为有一个只能往前面连的限制,所以还要可持久化.(duliu) 一直以来我都是写dinicdinicdinic做 ...

随机推荐

  1. 2013-7-31hibernate二级缓存

    难得闲 Fckeditor Fckconfig.js大部分配置都在这里面, 增加字体:         程序代码: FCKConfig.FontNames = 'Arial;Comic Sans MS ...

  2. route add提示: "SIOCADDRT: No such process

    解决方法如下: 原因: There are multiple known causes for this error: - You attempted to set a route specific ...

  3. HDU 6194 string string string 2017沈阳网络赛 后缀数组

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 题意:告诉你一个字符串和k , 求这个字符串中有多少不同的子串恰好出现了k 次. 解法:后缀数组 ...

  4. mac 上 sublime text2 快捷键

    打开/前往: ⌘T 前往文件 ⌘⌃P 前往项目⌘R 前往 method⌘⇧P 命令提示⌃G 前往行⌃ ` python 控制台 编辑:⌘L 选择行 (重复按下将下一行加入选择)⌘D 选择词 (重复按下 ...

  5. spring源码解析--事务篇(前篇)

    对于每一个JAVA程序员,spring应该是再熟悉不过的框架了,它的功能有多强大我就不多说了,既然他有这么强大的功能,是如何实现的呢?这个就需要从他的原理去了解,而最直接了解原理的方式莫过于源码.当然 ...

  6. bzoj 2819(DFS序+树状数组+博弈+lca)

    2819: Nim Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2045  Solved: 795[Submit][Status][Discuss] ...

  7. 计算 Python (list or array) 相同索引元素相等的个数

    上代码: a = [2, 3, 3, 1, 1, 3, 3, 3, 2, 1, 3, 1, 3, 2, 2, 2, 3, 1, 2, 3, 2, 3, 1, 1, 2, 1, 1, 1, 2, 2, ...

  8. 使用OpenSSL自签发服务器https证书

    OpenSSL官方推荐win32可执行文件版下载:http://www.slproweb.com/products/Win32OpenSSL.html ca.key CA私钥: openssl gen ...

  9. day1作业二:多级菜单

        作业二:多级菜单 1.三级菜单 2.可以次选择进入各子菜单 3.所需新知识点:列表.字典 4.打印b回到上一层 5.打印q退出循环 流程图如下: readme: (1)存储三级菜单的字典;设置 ...

  10. (转)Where与Having的总结

    Where 是一个约束声明,使用Where来约束来之数据库的数据,Where是在结果返回之前起作用的,且Where中不能使用聚合函数. Having 是一个过滤声明,是在查询返回结果集以后对查询结果进 ...