昨天考试被教育了一波。为了学习一下\(T3\)的科技,我就找到了这个远古时期的\(cf\)题(虽然最后\(T3\)还是不会写吧\(QAQ\))

顾名思义,这个题目其实可以建成一个费用流的模型。我们用流量来限制区间个数,用费用强迫它每次每次选择最大的区间就可以啦。但是因为询问很多,复杂度似乎不行,于是就有了这种神奇的科技——线段树模拟费用流。

在原先的费用流模型里,我们有正反两种边,而反向边的意义就在于,在每一次增广的时候可以反悔以前的操作,把局部最优向更大范围的局部更优优化。

参考反向边的原理,我们可以想象出来:如果对这个区间,我们每次都取用最大子区间,并在取用这个最大子区间以后将其价值变为负数,不就可以模拟费用流的行为了嘛?这样做的复杂度是\(O(NMlogN)\)的,可以解决更大数据范围的问题。

算法很好理解,关键是千万不要把代码写挂\(QwQ\),真的不是很好调啊\(TwT\)


  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. struct dat {
  4. int s; //sum of sequence
  5. int lmx, lmxp; //left -> max_val && it's pos
  6. int lmn, lmnp; //left -> min_val && it's pos
  7. int rmx, rmxp; //righ -> max_val && it's pos
  8. int rmn, rmnp; //righ -> min_val && it's pos
  9. int smx, smxl, smxr; //sub -> max_val && it's pos (l, r)
  10. int smn, smnl, smnr; //sub -> min_val && it's pos (l, r)
  11. dat (int pos = 0, int val = 0){
  12. lmxp = lmnp = rmxp = rmnp = smxl = smxr = smnl = smnr = pos;
  13. s = lmx = lmn = rmx = rmn = smx = smn = val;
  14. //对单个的点进行数据更新
  15. }
  16. }T[400010];
  17. dat operator + (dat l, dat r){
  18. dat u;
  19. u.s = l.s+r.s; //先更新关于和的数据
  20. if (l.lmx > l.s + r.lmx) { //max_left's pos 是否越过 mid
  21. u.lmx = l.lmx;
  22. u.lmxp = l.lmxp;
  23. } else {
  24. u.lmx = l.s + r.lmx;
  25. u.lmxp = r.lmxp;
  26. }
  27. if (r.rmx > r.s + l.rmx) { //max_righ's pos 是否越过 mid
  28. u.rmx = r.rmx;
  29. u.rmxp = r.rmxp;
  30. } else {
  31. u.rmx = r.s + l.rmx;
  32. u.rmxp = l.rmxp;
  33. }
  34. if (l.lmn < l.s + r.lmn) { //min_left's pos 是否越过 mid
  35. u.lmn = l.lmn;
  36. u.lmnp = l.lmnp;
  37. } else {
  38. u.lmn = l.s + r.lmn;
  39. u.lmnp = r.lmnp;
  40. }
  41. if (r.rmn < r.s + l.rmn) { //min_righ's pos 是否越过 mid
  42. u.rmn = r.rmn;
  43. u.rmnp = r.rmnp;
  44. } else {
  45. u.rmn = r.s + l.rmn;
  46. u.rmnp = l.rmnp;
  47. }
  48. if (l.smx > r.smx) { //最大子段 in left / righ
  49. u.smx = l.smx;
  50. u.smxl = l.smxl;
  51. u.smxr = l.smxr;
  52. } else {
  53. u.smx = r.smx;
  54. u.smxl = r.smxl;
  55. u.smxr = r.smxr;
  56. }
  57. if (l.rmx + r.lmx > u.smx){ //最大子段是否越过 mid
  58. u.smx = l.rmx + r.lmx;
  59. u.smxl = l.rmxp;
  60. u.smxr = r.lmxp;
  61. }
  62. if (l.smn < r.smn) { //最小子段 in left / righ
  63. u.smn = l.smn;
  64. u.smnl = l.smnl;
  65. u.smnr = l.smnr;
  66. } else {
  67. u.smn = r.smn;
  68. u.smnl = r.smnl;
  69. u.smnr = r.smnr;
  70. }
  71. if (l.rmn + r.lmn < u.smn) { //最小子段是否跨过 mid
  72. u.smn = l.rmn + r.lmn;
  73. u.smnl = l.rmnp;
  74. u.smnr = r.lmnp;
  75. }
  76. return u;
  77. }
  78. #define ls (x << 1)
  79. #define rs (x << 1 | 1)
  80. void pushup (int x) {
  81. T[x] = T[ls] + T[rs];
  82. }
  83. int a[100010];
  84. void build (int l, int r, int x) {
  85. if (l == r) {
  86. T[x] = dat (l, a[l]);
  87. return;
  88. }
  89. int mid = (l + r) >> 1;
  90. build (l, mid, ls);
  91. build (mid + 1, r, rs);
  92. pushup (x);
  93. }
  94. int f[400010];
  95. void rev (int x) {
  96. dat &u = T[x];
  97. // max 变成 min
  98. swap (u.lmx, u.lmn);
  99. swap (u.lmxp, u.lmnp);
  100. swap (u.rmx, u.rmn);
  101. swap (u.rmxp, u.rmnp);
  102. swap (u.smx, u.smn);
  103. swap (u.smxl, u.smnl);
  104. swap (u.smxr, u.smnr);
  105. f[x] ^= 1;
  106. u.lmx *= -1;
  107. u.lmn *= -1;
  108. u.rmx *= -1;
  109. u.rmn *= -1;
  110. u.smx *= -1;
  111. u.smn *= -1;
  112. u.s *= -1;
  113. }
  114. void pushdown (int x) {
  115. if(f[x]) {
  116. rev (ls);
  117. rev (rs);
  118. f[x] = 0;
  119. }
  120. }
  121. void modify (int p, int v, int l, int r, int x) {
  122. if (l == r) {
  123. T[x] = dat (l, v);
  124. return;
  125. }
  126. pushdown (x);
  127. int mid = (l + r) >> 1;
  128. if (p <= mid) {
  129. modify (p, v, l, mid, ls);
  130. } else {
  131. modify (p, v, mid + 1, r, rs);
  132. }
  133. pushup (x);
  134. }
  135. void reverse (int L, int R, int l, int r, int x) {
  136. //其实就是取用啦
  137. if (L <= l && r <= R) return rev (x);
  138. pushdown (x);
  139. int mid = (l + r) >> 1;
  140. if (L <= mid) reverse (L, R, l, mid, ls);
  141. if (mid < R) reverse (L, R, mid + 1, r, rs);
  142. pushup (x);
  143. }
  144. dat query (int L, int R, int l, int r, int x) {
  145. //求[l, r]区间内的最大值嘛
  146. if (L <= l && r <= R) return T[x];
  147. pushdown (x);
  148. int mid = (l + r) >> 1;
  149. if (R <= mid) return query (L, R, l, mid, ls); //如果区间全在左边
  150. if (mid < L) return query (L, R, mid + 1, r, rs); //如果区间全在右边
  151. return query (L, R, l, mid, ls) + query (L, R, mid + 1, r, rs); //跨 mid 了 QwQ
  152. }
  153. int L[30], R[30], top;
  154. int n, m, x, y, k, opt;
  155. int main () {
  156. cin >> n;
  157. for (int i = 1; i <= n; ++i) {
  158. cin >> a[i];
  159. }
  160. build (1, n, 1);
  161. cin >> m;
  162. for (int i = 1; i <= m; ++i) {
  163. cin >> opt >> x >> y;
  164. if (opt == 0) {
  165. modify (x, y, 1, n, 1); //把点 x 的值改为 y
  166. } else {
  167. cin >> k; //在[x, y]之间取 k 段的最大值
  168. int ans = 0;
  169. for (int j = 1; j <= k; ++j) {
  170. dat t = query (x, y, 1, n, 1);
  171. if (t.smx <= 0) break;
  172. //选至多 k 段, 可以少选 !
  173. ans += t.smx;
  174. L[++top] = t.smxl, R[top] = t.smxr;
  175. reverse (L[top], R[top], 1, n, 1);
  176. }
  177. while (top) {
  178. reverse (L[top], R[top], 1, n, 1);
  179. top = top - 1;
  180. }
  181. cout << ans << endl;
  182. }
  183. }
  184. }

【CF280D】 k-Maximum Subsequence Sum ,线段树模拟费用流的更多相关文章

  1. [BZOJ3638 && BZOJ3272]带修区间不相交最大K子段和(线段树模拟费用流)

    https://www.cnblogs.com/DaD3zZ-Beyonder/p/5634149.html k可重区间集问题有两种建图方式,可能这一种才可以被线段树优化. 换个角度看,这也是一个类似 ...

  2. 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

    [BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...

  3. CF280D k-Maximum Subsequence Sum(线段树)

    在做这题时我一开始把\(tag\)写入了结构体 #include <iostream> #include <cstdio> #include <cstring> # ...

  4. 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...

  5. Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]

    洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...

  6. BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836 (Codeforces) http://codeforces.com ...

  7. BZOJ 5326 [JSOI2017]博弈 (模拟费用流、线段树)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5326 题解 终于成为第8个A掉这题的人--orz tzw神仙早我6小时 本以为这东西常数 ...

  8. 1007 Maximum Subsequence Sum (25分) 求最大连续区间和

    1007 Maximum Subsequence Sum (25分)   Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A ...

  9. 中国大学MOOC-陈越、何钦铭-数据结构-2015秋 01-复杂度2 Maximum Subsequence Sum (25分)

    01-复杂度2 Maximum Subsequence Sum   (25分) Given a sequence of K integers { N​1​​,N​2​​, ..., N​K​​ }. ...

随机推荐

  1. ABP 番外篇-容器

    一. @using YD.CloudTimetable.Web.Areas.AppAreaName.Startup @{ ViewBag.CurrentPageName = AppAreaNamePa ...

  2. Lambda表达式Contains方法(等价于SQL语句中的like)使用注意事项

    貌似已经半年多没写一篇帖子了,充分的说明要么老总一天折腾的让人心齐疲惫,没心情去写:要么另外一种可能就是自己不思进取,说白了就是懒.好在这种状态在今天被打破了.MoNey加油. 众所周知,想在Enti ...

  3. C-Lodop提示“网页还没下载完毕,请稍等一下再操作.”

    该提示在Lodop旧版本中是: 提示"WebSocket没准备好,点确定继续",提示“C-Lodop没准备好”,新版本修改了该提示的描述“网页还没下载完毕,请稍等一下再操作.”,让 ...

  4. Civil 3D 2017本地化中VBA程序移植到2018版中

    中国本地化包简直就是一块鸡肋, 但对于某些朋友来说还真离不了: 可惜中国本地化包的推出一直滞后, 在最新版软件出来后1年多, 本地化还不一定能够出来, 即使出来了, 也只能是购买了速博服务的用户才能得 ...

  5. CF558E-A Simple Task-线段树+计数排序

    计数排序的原理,只要知道了有几个数比i小,就可以知道i的位置 这道题只有26个字母,搞26颗线段树,然后区间更新 #include <cstdio> #include <cstrin ...

  6. C - A Simple Problem with Integers POJ - 3468 线段树模版(区间查询区间修改)

    参考qsc大佬的视频 太强惹 先膜一下 视频在b站 直接搜线段树即可 #include<cstdio> using namespace std; ; int n,a[maxn]; stru ...

  7. prufer序列

    介绍 其实是\(pr\ddot{u}fer\)序列 什么是prufer序列? 我们认为度数为\(1\)的点是叶子节点 有一颗无根树,每次选出编号最小的叶子节点,加到当前prufer序列的后面,然后删掉 ...

  8. CCPC-Wannafly Winter Camp Day1 (Div2, onsite) A B C E F I J

    A 机器人 链接:https://www.cometoj.com/contest/7/problem/A?problem_id=92 思路: 分两大类讨论: 1. B区没有点: (1)点都在起点左边 ...

  9. SCOI2016幸运数字(树剖/倍增/点分治+线性基)

    题目链接 loj luogu 题意 求树上路径最大点权异或和 自然想到(维护树上路径)+ (维护最大异或和) 那么有三种方法可以选择 1.树剖+线性基 2.倍增+线性基 3.点分治+线性基 至于线性基 ...

  10. vxlan和vlan数据报文

    802.1Q标准的以太网帧格式增加了802.1Q字段,该字段包含了Type.PRI.CFI和VID 4个部分,各个部分的含义如下: ·Type:长度为2 bytes,表示帧类型,802.1Q tag帧 ...