[Codeforces 280D]k-Maximum Subsequence Sum(线段树)

题面

给出一个序列,序列里面的数有正有负,有两种操作

1.单点修改

2.区间查询,在区间中选出至多k个不相交的子区间,使得这至多k个子区间中数的和最大

分析

极其毒瘤的线段树,要维护18个变量

首先考虑查询k=1的情况,是常见的线段树模型。维护区间最大连续和,区间最大前缀和,区间最大后缀和。合并的时候分类讨论一下即可,这里不再赘述。

如果k>1怎么办呢。实际上可以贪心,每次取1个最大子区间,然后把子区间内的值取反。再继续取最大子区间。如果此时最大子区间的和已经<0,就不取了。

正确性可以感性理解一下。假如我们的区间内的数为{7,-2,3,-10},k=2.第一次取出的序列为{7,-2,3},然后取反,变成了{-7,2,-3,10}。再取一次就得到了{2}.把这两个子区间加起来,我们发现和为7+(-2)+3+2=7+3,正好是和最大的两个序列{7}{3}.这里的取反操作,实际上起到了把一个区间断成多个的效果。(upd:这里用模拟费用流里退流的思想,可以严格证明正确性)

那么我们考虑具体实现,除了区间最大连续和,区间最大前缀和,区间最大后缀和,我们还要维护对应连续和的起点和终点。取反实际上比较简单,只要再维护区间最小连续和等变量,取反的时候交换最大最小值,并乘上-1即可。

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define maxn 100000
  6. #define maxk 20
  7. using namespace std;
  8. inline void qread(int &x){
  9. x=0;
  10. int sign=1;
  11. char c=getchar();
  12. while(c<'0'||c>'9'){
  13. if(c=='-') sign=-1;
  14. c=getchar();
  15. }
  16. while(c>='0'&&c<='9'){
  17. x=x*10+c-'0';
  18. c=getchar();
  19. }
  20. x=x*sign;
  21. }
  22. inline void qprint(int x){
  23. if(x<0){
  24. putchar('-');
  25. qprint(-x);
  26. }else if(x==0){
  27. putchar('0');
  28. return;
  29. }else{
  30. if(x/10>0) qprint(x/10);
  31. putchar('0'+x%10);
  32. }
  33. }
  34. int n,m;
  35. int a[maxn+5];
  36. struct val{
  37. int sum;//区间和
  38. //最小值相关
  39. int lmin;//最小前缀和
  40. int lminp;//最小前缀和的位置为[l,lminp],线段树节点里已经记录了[l,r]
  41. int rmin;//最小后缀和
  42. int rminp;//最小后缀和的位置为[rminp,r]
  43. int minv;//最小连续和
  44. int minpl;//最小连续和的起点
  45. int minpr;//最小连续和的终点
  46. //最大值相关
  47. int lmax;
  48. int lmaxp;
  49. int rmax;
  50. int rmaxp;
  51. int maxv;
  52. int maxpl;
  53. int maxpr;
  54. friend val operator + (val lson,val rson){
  55. val ans;
  56. ans.sum=lson.sum+rson.sum;
  57. ans.lmin=lson.lmin;
  58. ans.lminp=lson.lminp;
  59. if(lson.sum+rson.lmin<ans.lmin){
  60. ans.lmin=lson.sum+rson.lmin;
  61. ans.lminp=rson.lminp;
  62. }
  63. ans.rmin=rson.rmin;
  64. ans.rminp=rson.rminp;
  65. if(rson.sum+lson.rmin<ans.rmin){
  66. ans.rmin=rson.sum+lson.rmin;
  67. ans.rminp=lson.rminp;
  68. }
  69. int minv=min(min(lson.minv,rson.minv),lson.rmin+rson.lmin);
  70. ans.minv=minv;
  71. if(lson.minv==minv){
  72. ans.minpl=lson.minpl;
  73. ans.minpr=lson.minpr;
  74. }else if(rson.minv==minv){
  75. ans.minpl=rson.minpl;
  76. ans.minpr=rson.minpr;
  77. }else{
  78. ans.minpl=lson.rminp;
  79. ans.minpr=rson.lminp;
  80. }
  81. ans.lmax=lson.lmax;
  82. ans.lmaxp=lson.lmaxp;
  83. if(lson.sum+rson.lmax>ans.lmax){
  84. ans.lmax=lson.sum+rson.lmax;
  85. ans.lmaxp=rson.lmaxp;
  86. }
  87. ans.rmax=rson.rmax;
  88. ans.rmaxp=rson.rmaxp;
  89. if(rson.sum+lson.rmax>ans.rmax){
  90. ans.rmax=rson.sum+lson.rmax;
  91. ans.rmaxp=lson.rmaxp;
  92. }
  93. int maxv=max(max(lson.maxv,rson.maxv),lson.rmax+rson.lmax);
  94. ans.maxv=maxv;
  95. if(lson.maxv==maxv){
  96. ans.maxpl=lson.maxpl;
  97. ans.maxpr=lson.maxpr;
  98. }else if(rson.maxv==maxv){
  99. ans.maxpl=rson.maxpl;
  100. ans.maxpr=rson.maxpr;
  101. }else{
  102. ans.maxpl=lson.rmaxp;
  103. ans.maxpr=rson.lmaxp;
  104. }
  105. return ans;
  106. }
  107. void reverse(){
  108. sum=-sum;
  109. lmin=-lmin;
  110. lmax=-lmax;
  111. swap(lmin,lmax);
  112. swap(lminp,lmaxp);
  113. rmin=-rmin;
  114. rmax=-rmax;
  115. swap(rmin,rmax);
  116. swap(rminp,rmaxp);
  117. minv=-minv;
  118. maxv=-maxv;
  119. swap(minv,maxv);
  120. swap(minpl,maxpl);
  121. swap(minpr,maxpr);
  122. }
  123. void set(int pos,int val){
  124. sum=lmin=lmax=rmin=rmax=minv=maxv=val;
  125. lminp=lmaxp=rminp=rmaxp=minpl=maxpl=minpr=maxpr=pos;
  126. }
  127. void print(){
  128. printf("val: maxv=%d lmax=%d rmax=%d\n",maxv,lmax,rmax);
  129. }
  130. };
  131. struct segment_tree{
  132. struct node{
  133. int l;
  134. int r;
  135. int sum;
  136. int mark;//区间-1(翻转max,min) 标记
  137. val v;
  138. }tree[maxn*4+5];
  139. void push_up(int pos){
  140. tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
  141. }
  142. void build(int l,int r,int pos){
  143. tree[pos].l=l;
  144. tree[pos].r=r;
  145. if(l==r){
  146. tree[pos].v.set(l,a[l]);
  147. return;
  148. }
  149. int mid=(l+r)>>1;
  150. build(l,mid,pos<<1);
  151. build(mid+1,r,pos<<1|1);
  152. push_up(pos);
  153. // printf("[%d,%d]: ",l,r);
  154. // tree[pos].v.print();
  155. }
  156. void push_down(int pos){
  157. if(tree[pos].mark){
  158. tree[pos<<1].mark^=1;
  159. tree[pos<<1].v.reverse();
  160. tree[pos<<1|1].mark^=1;
  161. tree[pos<<1|1].v.reverse();
  162. tree[pos].mark=0;
  163. }
  164. }
  165. void update_segment(int L,int R,int pos){
  166. if(L<=tree[pos].l&&R>=tree[pos].r){
  167. tree[pos].mark^=1;
  168. tree[pos].v.reverse();
  169. return;
  170. }
  171. push_down(pos);
  172. int mid=(tree[pos].l+tree[pos].r)>>1;
  173. if(L<=mid) update_segment(L,R,pos<<1);
  174. if(R>mid) update_segment(L,R,pos<<1|1);
  175. push_up(pos);
  176. }
  177. void update_point(int upos,int val,int pos){
  178. if(tree[pos].l==tree[pos].r){
  179. tree[pos].v.set(tree[pos].l,val);
  180. return;
  181. }
  182. push_down(pos);
  183. int mid=(tree[pos].l+tree[pos].r)>>1;
  184. if(upos<=mid) update_point(upos,val,pos<<1);
  185. else update_point(upos,val,pos<<1|1);
  186. push_up(pos);
  187. }
  188. val query(int L,int R,int pos){
  189. if(L<=tree[pos].l&&R>=tree[pos].r){
  190. return tree[pos].v;
  191. }
  192. push_down(pos);
  193. int mid=(tree[pos].l+tree[pos].r)>>1;
  194. val lans,rans;
  195. lans.set(0,0);
  196. rans.set(0,0);
  197. if(L<=mid){
  198. lans=query(L,R,pos<<1);
  199. }
  200. if(R>mid){
  201. rans=query(L,R,pos<<1|1);
  202. }
  203. if(lans.maxpl==0) return rans;
  204. else if(rans.maxpl==0) return lans;
  205. else return lans+rans;
  206. }
  207. }T;
  208. val tmp[maxk+5];
  209. int solve(int l,int r,int k){
  210. int sz=0;
  211. int ans=0;
  212. for(int i=1;i<=k;i++){
  213. tmp[++sz]=T.query(l,r,1);
  214. if(tmp[sz].maxv<0){
  215. sz--;
  216. break;
  217. }
  218. ans+=tmp[sz].maxv;
  219. T.update_segment(tmp[sz].maxpl,tmp[sz].maxpr,1);
  220. }
  221. for(int i=sz;i>=1;i--){
  222. T.update_segment(tmp[i].maxpl,tmp[i].maxpr,1);
  223. }
  224. return ans;
  225. }
  226. int main(){
  227. //#ifndef LOCAL
  228. // freopen("easy.in","r",stdin);
  229. // freopen("easy.out","w",stdout);
  230. //#endif
  231. int op,x,val,l,r,k;
  232. qread(n);
  233. for(int i=1;i<=n;i++) qread(a[i]);
  234. T.build(1,n,1);
  235. qread(m);
  236. for(int i=1;i<=m;i++){
  237. qread(op);
  238. if(op==0){
  239. qread(x);
  240. qread(val);
  241. T.update_point(x,val,1);
  242. }else{
  243. qread(l);
  244. qread(r);
  245. qread(k);
  246. qprint(solve(l,r,k));
  247. putchar('\n');
  248. }
  249. }
  250. }

[Codeforces 280D]k-Maximum Subsequence Sum(线段树)的更多相关文章

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

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

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

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

  3. Codeforces 834D The Bakery【dp+线段树维护+lazy】

    D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...

  4. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  5. 中国大学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​​ }. ...

  6. PAT1007:Maximum Subsequence Sum

    1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...

  7. PTA (Advanced Level) 1007 Maximum Subsequence Sum

    Maximum Subsequence Sum Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous su ...

  8. 【DP-最大子串和】PAT1007. Maximum Subsequence Sum

    1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...

  9. PAT Maximum Subsequence Sum[最大子序列和,简单dp]

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

  10. PAT甲 1007. Maximum Subsequence Sum (25) 2016-09-09 22:56 41人阅读 评论(0) 收藏

    1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...

随机推荐

  1. [翻译]解释JavaScript中的类型转换

    原文地址:JavaScript type coercion explained 类型转换是将值从一种类型转换为另一种类型的过程(比如字符串转换为数值,对象转换为布尔值,等等).任何类型,无论是原始类型 ...

  2. Webpack3.X版 学习全文

    如果你webpack用的是4.x版本,此文章部分知识有所改动,所以学习时尽量使用3.x的版本. 本文讲解的是Webpack3.0+的知识,努力做到全网最好的webpack3.0教程.文章通过一个半月的 ...

  3. idea hibernate console 执行hql报错

    报错信息 hql> select a from GDXMZD a[2019-08-29 13:45:01] org.hibernate.service.spi.ServiceException: ...

  4. postgresql相关sql集锦

    1.类似于oracle的listagg->string_agg SELECT area_county,)total FROM project_info GROUP BY area_county ...

  5. Flutter-網絡請求

    Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 HttpClient.第三方网络请求 http以及 Flutter 中的 Dio.我们可以比 ...

  6. nginx主配置文件学习,以及nginx的反向代理和负载均衡

    1.nginx.conf主配置文件学习 worker_processes : 表示nginx的进程数,根据CPU的核数来定义,起到优化的作用.通过cat /proc/cpuinfo来查看核数 even ...

  7. D0g3_Trash_Pwn_Writeup

    Trash Pwn 下载文件 1 首先使用checksec查看有什么保护 可以发现,有canary保护(Stack),堆栈不可执行(NX),地址随机化没有开启(PIE) 2 使用IDA打开看看 mai ...

  8. 调试IPV6

    从Mac分享IPV6 WIFI的方法: 按住opition + 系统设置中的share 进入 如果被拒了要上诉或者回复审核团队邮件,可以参考这个写: 尊敬的APP审查委员会: 您们好!我们希望将自己开 ...

  9. 如何安装 mcrypt

    #cd libmcrypt-2.5.8 #./configure #make #make install 说明:libmcript默认安装在/usr/local3.安装mhash #tar -zxvf ...

  10. CKEDITOR Copying images from word

    自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了.一般情况下我们将Word内容粘贴到Web编辑器(富文本编辑器) ...