题意:从某个区间内最多选择k个数,使得和最大

思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数和。

划分树:

[1  6  3  8  5  4  7  2]

[6  8  5  7][1  3  4  2]

[8  7][6  5][3  4][1  2]

[8][7][6][5][4][3][2][1]

把快排的结果从上至下依次放入线段树,就构成了划分树,划分的意思就是选定一个数,把原序列分成两块,使得左边整体大于右边,而一个块内的数在原序列的相对位置不发生变化。划分树的过程基本就是初始化,建树,和查找。初始化只要把原序列导入划分树的根就行了,建树过程依赖排好序的原序列来得到用来“划分”的数,查找过程也很简单,不需要像线段树那样将询问分解,在树上查找答案的时候是左右子树二选一。

划分树一般用来求区间第k大数,对于划分树为什么可以求区间k大和,见代码。

  1. #pragma comment(linker, "/STACK:10240000,10240000")
  2.  
  3. #include <iostream>
  4. #include <cstdio>
  5. #include <algorithm>
  6. #include <cstdlib>
  7. #include <cstring>
  8. #include <map>
  9. #include <queue>
  10. #include <deque>
  11. #include <cmath>
  12. #include <vector>
  13. #include <ctime>
  14. #include <cctype>
  15. #include <set>
  16. #include <bitset>
  17. #include <functional>
  18. #include <numeric>
  19. #include <stdexcept>
  20. #include <utility>
  21.  
  22. using namespace std;
  23.  
  24. #define mem0(a) memset(a, 0, sizeof(a))
  25. #define mem_1(a) memset(a, -1, sizeof(a))
  26. #define lson l, m, rt << 1
  27. #define rson m + 1, r, rt << 1 | 1
  28. #define rep_up0(a, b) for (int a = 0; a < (b); a++)
  29. #define rep_up1(a, b) for (int a = 1; a <= (b); a++)
  30. #define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
  31. #define rep_down1(a, b) for (int a = b; a > 0; a--)
  32. #define all(a) (a).begin(), (a).end()
  33. #define lowbit(x) ((x) & (-(x)))
  34. #define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
  35. #define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
  36. #define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
  37. #define pchr(a) putchar(a)
  38. #define pstr(a) printf("%s", a)
  39. #define sstr(a) scanf("%s", a)
  40. #define sint(a) scanf("%d", &a)
  41. #define sint2(a, b) scanf("%d%d", &a, &b)
  42. #define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
  43. #define pint(a) printf("%d\n", a)
  44. #define test_print1(a) cout << "var1 = " << a << endl
  45. #define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
  46. #define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl
  47. #define mp(a, b) make_pair(a, b)
  48. #define pb(a) push_back(a)
  49.  
  50. typedef unsigned int uint;
  51. typedef long long LL;
  52. typedef pair<int, int> pii;
  53. typedef vector<int> vi;
  54.  
  55. const int dx[] = {, , -, , , , -, -};
  56. const int dy[] = {-, , , , , -, , - };
  57. const int maxn = 1e4 + ;
  58. const int md = 1e9 + ;
  59. const int inf = 1e9 + ;
  60. const LL inf_L = 1e18 + ;
  61. const double pi = acos(-1.0);
  62. const double eps = 1e-;
  63.  
  64. template<class T>T gcd(T a, T b){return b==?a:gcd(b,a%b);}
  65. template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
  66. template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
  67. template<class T>T condition(bool f, T a, T b){return f?a:b;}
  68. template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
  69. int make_id(int x, int y, int n) { return x * n + y; }
  70.  
  71. /// 划分树求区间前k大和
  72. /// 关于为什么可以用前缀和来求前k大的和:对于一个询问区间,如果前k大在左子树,
  73. /// 那么这k个数会按原顺序依次进入左子树,进入左子树后它们之间不会有其它不是前k大的数,
  74. /// 所以对应到下一层也是连续的一段,于是可用前缀和来得到,对于前k大跨区间的情况同理。
  75. /// 区间范围为:1 ~ n
  76. struct PartitionTree {
  77. int val[][maxn], sum[][maxn], cnt[][maxn];//划分后的结果,前缀和,进入左子树的个数
  78. void init(int a[], int l, int r) {
  79. mem0(val);
  80. mem0(sum);
  81. mem0(cnt);
  82. for (int i = l; i <= r; i ++) sum[][i] = sum[][i - ] + (val[][i] = a[i]);
  83. }
  84. /// 向下更新val和sum数组,同时维护cnt数组的值
  85. void build(int b[], int l, int r, int dep) {
  86. if (l == r) return ;
  87. int m = (l + r) >> ;
  88. /// c记录大于中位数的数的个数,cc记录进入左子树的等于中位数的数的个数,由于相等情况的存在,这个信息必不可少。
  89. int lc = , rc = , lt = (r - l + ) >> , c = , cc = ;
  90. for (int i = l; i <= r; i ++) c += val[dep][i] > b[m];
  91. for (int i = l; i <= r; i ++) {
  92. cnt[dep][i] = cnt[dep][i - ];
  93. if (lc < lt && (val[dep][i] > b[m] || val[dep][i] == b[m] && cc < lt - c)) {
  94. val[dep + ][l + lc ++] = val[dep][i];
  95. cnt[dep][i] ++;
  96. if (val[dep][i] == b[m]) cc ++;
  97. }
  98. else {
  99. val[dep + ][m + + rc ++] = val[dep][i];
  100. }
  101. }
  102.  
  103. for (int i = l; i <= r; i ++) sum[dep + ][i] = sum[dep + ][i - ] + val[dep + ][i];
  104. build(b, l, m, dep + );
  105. build(b, m + , r, dep + );
  106. }
  107. int query_ksum(int L, int R, int k, int l, int r, int dep) {
  108. if (k == ) return ;
  109. if (l == r) return val[dep][l];
  110. int m = (l + r) >> , c = cnt[dep][R] - cnt[dep][L - ];
  111. if (c >= k) {
  112. int x = cnt[dep][L - ] - cnt[dep][l - ], y = cnt[dep][R] - cnt[dep][l - ];
  113. return query_ksum(l + x, l + y - , k, l, m, dep + );
  114. }
  115. else {
  116. int x0 = cnt[dep][L - ] - cnt[dep][l - ], x = L - l - cnt[dep][L - ] + cnt[dep][l - ], y = R - l + - cnt[dep][R] + cnt[dep][l - ];
  117. return sum[dep + ][l + x0 - + c] - sum[dep + ][l + x0 - ] + query_ksum(m + + x, m + + y - , k - c, m + , r, dep + );
  118. }
  119. }
  120.  
  121. };
  122. PartitionTree pt;
  123. pii node[maxn];
  124. int a[maxn], b[maxn], p[maxn];
  125.  
  126. bool cmp(int i, int j) {
  127. return i > j;
  128. }
  129. int main() {
  130. //freopen("in.txt", "r", stdin);
  131. int n, m;
  132. while (cin >> n) {
  133. rep_up0(i, n) {
  134. sint2(node[i].first, node[i].second);
  135. max_update(node[i].second, );
  136. }
  137. sort(node, node + n);
  138. rep_up0(i, n) {
  139. b[i] = a[i] = node[i].second;
  140. p[i] = node[i].first;
  141. }
  142. sort(b, b + n, cmp);
  143. pt.init(a - , , n);
  144. pt.build(b - , , n, );
  145. cin >> m;
  146. rep_up0(i, m) {
  147. int l, r, k;
  148. sint3(l, r, k);
  149. l = lower_bound(p, p + n, l) - p + ;
  150. r = upper_bound(p, p + n, r) - p;
  151. min_update(k, r - l + );
  152. printf("%d\n", pt.query_ksum(l, r, k, , n, ));
  153. }
  154. cout << endl;
  155. }
  156. return ;
  157. }

[csu/coj 1080]划分树求区间前k大数和的更多相关文章

  1. [hdu2665]Kth number(划分树求区间第k大)

    解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...

  2. HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)

    题意:在区间中找一个数,求出该区间每个数与这个数距离的总和,使其最小 找的数字是中位数(若是偶数个,则中间随便哪个都可)接着找到该区间比此数大的数的总和 区间中位数可以使用划分树,然后在其中记录:每层 ...

  3. HDOJ题目4417 Super Mario(划分树求区间比k小的个数+二分)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  4. 线段树维护区间前k小

    线段树维护区间前k小 $ solution: $ 觉得超级钢琴太麻烦?在这里线段树提供一条龙服务 . 咳咳,开始讲正题!这道题我们有一个和超级钢琴复杂度一样 $ ~O(~\sum x\times lo ...

  5. hdu4417 主席树求区间小于等于K

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417   Problem Description Mario is world-famous plum ...

  6. 主席树——求区间第k个不同的数字(向右密集hdu5919)

    和向左密集比起来向右密集只需要进行小小的额修改,就是更新的时候从右往左更新.. 自己写的被卡死时间.不知道怎么回事,和网上博客的没啥区别.. /* 给定一个n个数的序列a 每次询问区间[l,r],求出 ...

  7. [poj2104]kth-number(归并树求区间第k大)

    复杂度:$O(nlog^3n)$ #include<cstdio> #include<cstring> #include<algorithm> #include&l ...

  8. 主席树--动态区间第k小

    主席树--动态区间第\(k\)小 模板题在这里洛谷2617. 先对几个问题做一个总结: 阅读本文需要有主席树的基础,也就是通过区间kth的模板题. 静态整体kth: sort一下找第k小,时间复杂度\ ...

  9. 2016年湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)

    原题链接 http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 Description Bobo has a balanced parenthes ...

随机推荐

  1. Ubuntu安装Elasticsearch6.3

    本文使用的 Ubuntu 版本信息: Distributor ID: Ubuntu Description: Ubuntu LTS Release: 16.04 Codename: xenial 1. ...

  2. 你知道什么是 GitHub Action 么?

    本文是 GitHub Action 的入门教程,如您已有相关使用经验可以直接关掉. GitHub Action 是 GitHub 于 2018 年 10 月推出的一个 CI\CD 服务. 之前一直都是 ...

  3. SpringCloud-Gateway 网关路由、断言、过滤

    Gateway 简介 是什么? Spring Cloud 全家桶中有个很重要的组件:网关.在 1.x 版本中使用的是 Zuul 网关,但是到了 2.x,由于Zuul的升级不断跳票,Spring Clo ...

  4. ADO.Net和Entity Framework的区别联系

    它们有以下几点区别:1,ADO.Net是开发人员自己select.update等写sql语句,来实现对数据库的增删改查等操作:采用EF进行开发操作数据库的时候,只需要操作对象,这样做使开发更方便,此时 ...

  5. C# 反射(一)

    刚工作没多久,需要对以往的知识进行复习和巩固.先讲讲最近在公司常用到的反射机制. 反射(Reflection):提供了封装程序集.模块和类型的对象(Type 类型).可以使用反射动态创建类型的实例,将 ...

  6. ES6的 Iterator 遍历器到底是什么?

    这节课要讲的是ES6中的Iterator. for...of为啥不遍历Object对象 第十三节我们讲了简单又实用的for...of,我们可以使用它来遍历数组,字符串,Set和Map结构,但是有没有发 ...

  7. 总结php删除html标签和标签内的内容的方法

    来源:https://www.cnblogs.com/shaoguan/p/7336984.html 经常扒别人网站文章的坑们:我是指那种批量式采集的压根不看内容的:少不了都会用到删除html标签的函 ...

  8. CG-CTF(5)

    CG-CTF https://cgctf.nuptsast.com/challenges#Web 续上~ 第二十二题:SQL注入1 点击Source: 分析: mysql_select_db()函数: ...

  9. 理解分布式一致性:拜占庭容错与PBFT

    理解分布式一致性:拜占庭容错与PBFT 拜占庭问题 拜占庭容错BFT PBFT(Practical Byzantine Fault Tolerance) why 3f+1 ? PBFT 的优点 PBF ...

  10. SpringBoot应用操作Rabbitmq(topic交换器高级操作)

    一.topic交换器为主题交换器,可以根据路由key模糊匹配 实现模型图 二.实战 1.引入maven <dependency> <groupId>org.springfram ...