[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即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100000
#define maxk 20
using namespace std; inline void qread(int &x){
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(int x){
if(x<0){
putchar('-');
qprint(-x);
}else if(x==0){
putchar('0');
return;
}else{
if(x/10>0) qprint(x/10);
putchar('0'+x%10);
}
} int n,m;
int a[maxn+5];
struct val{
int sum;//区间和
//最小值相关
int lmin;//最小前缀和
int lminp;//最小前缀和的位置为[l,lminp],线段树节点里已经记录了[l,r]
int rmin;//最小后缀和
int rminp;//最小后缀和的位置为[rminp,r]
int minv;//最小连续和
int minpl;//最小连续和的起点
int minpr;//最小连续和的终点
//最大值相关
int lmax;
int lmaxp;
int rmax;
int rmaxp;
int maxv;
int maxpl;
int maxpr; friend val operator + (val lson,val rson){
val ans;
ans.sum=lson.sum+rson.sum; ans.lmin=lson.lmin;
ans.lminp=lson.lminp;
if(lson.sum+rson.lmin<ans.lmin){
ans.lmin=lson.sum+rson.lmin;
ans.lminp=rson.lminp;
} ans.rmin=rson.rmin;
ans.rminp=rson.rminp;
if(rson.sum+lson.rmin<ans.rmin){
ans.rmin=rson.sum+lson.rmin;
ans.rminp=lson.rminp;
} int minv=min(min(lson.minv,rson.minv),lson.rmin+rson.lmin);
ans.minv=minv;
if(lson.minv==minv){
ans.minpl=lson.minpl;
ans.minpr=lson.minpr;
}else if(rson.minv==minv){
ans.minpl=rson.minpl;
ans.minpr=rson.minpr;
}else{
ans.minpl=lson.rminp;
ans.minpr=rson.lminp;
} ans.lmax=lson.lmax;
ans.lmaxp=lson.lmaxp;
if(lson.sum+rson.lmax>ans.lmax){
ans.lmax=lson.sum+rson.lmax;
ans.lmaxp=rson.lmaxp;
} ans.rmax=rson.rmax;
ans.rmaxp=rson.rmaxp;
if(rson.sum+lson.rmax>ans.rmax){
ans.rmax=rson.sum+lson.rmax;
ans.rmaxp=lson.rmaxp;
} int maxv=max(max(lson.maxv,rson.maxv),lson.rmax+rson.lmax);
ans.maxv=maxv;
if(lson.maxv==maxv){
ans.maxpl=lson.maxpl;
ans.maxpr=lson.maxpr;
}else if(rson.maxv==maxv){
ans.maxpl=rson.maxpl;
ans.maxpr=rson.maxpr;
}else{
ans.maxpl=lson.rmaxp;
ans.maxpr=rson.lmaxp;
} return ans;
} void reverse(){
sum=-sum;
lmin=-lmin;
lmax=-lmax;
swap(lmin,lmax);
swap(lminp,lmaxp);
rmin=-rmin;
rmax=-rmax;
swap(rmin,rmax);
swap(rminp,rmaxp);
minv=-minv;
maxv=-maxv;
swap(minv,maxv);
swap(minpl,maxpl);
swap(minpr,maxpr);
} void set(int pos,int val){
sum=lmin=lmax=rmin=rmax=minv=maxv=val;
lminp=lmaxp=rminp=rmaxp=minpl=maxpl=minpr=maxpr=pos;
} void print(){
printf("val: maxv=%d lmax=%d rmax=%d\n",maxv,lmax,rmax);
}
}; struct segment_tree{
struct node{
int l;
int r;
int sum;
int mark;//区间-1(翻转max,min) 标记
val v;
}tree[maxn*4+5];
void push_up(int pos){
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
if(l==r){
tree[pos].v.set(l,a[l]);
return;
}
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
push_up(pos);
// printf("[%d,%d]: ",l,r);
// tree[pos].v.print();
}
void push_down(int pos){
if(tree[pos].mark){
tree[pos<<1].mark^=1;
tree[pos<<1].v.reverse();
tree[pos<<1|1].mark^=1;
tree[pos<<1|1].v.reverse();
tree[pos].mark=0;
}
}
void update_segment(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
tree[pos].mark^=1;
tree[pos].v.reverse();
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update_segment(L,R,pos<<1);
if(R>mid) update_segment(L,R,pos<<1|1);
push_up(pos);
}
void update_point(int upos,int val,int pos){
if(tree[pos].l==tree[pos].r){
tree[pos].v.set(tree[pos].l,val);
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(upos<=mid) update_point(upos,val,pos<<1);
else update_point(upos,val,pos<<1|1);
push_up(pos);
}
val query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].v;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
val lans,rans;
lans.set(0,0);
rans.set(0,0);
if(L<=mid){
lans=query(L,R,pos<<1);
}
if(R>mid){
rans=query(L,R,pos<<1|1);
}
if(lans.maxpl==0) return rans;
else if(rans.maxpl==0) return lans;
else return lans+rans;
}
}T; val tmp[maxk+5];
int solve(int l,int r,int k){
int sz=0;
int ans=0;
for(int i=1;i<=k;i++){
tmp[++sz]=T.query(l,r,1);
if(tmp[sz].maxv<0){
sz--;
break;
}
ans+=tmp[sz].maxv;
T.update_segment(tmp[sz].maxpl,tmp[sz].maxpr,1);
}
for(int i=sz;i>=1;i--){
T.update_segment(tmp[i].maxpl,tmp[i].maxpr,1);
}
return ans;
} int main(){
//#ifndef LOCAL
// freopen("easy.in","r",stdin);
// freopen("easy.out","w",stdout);
//#endif
int op,x,val,l,r,k;
qread(n);
for(int i=1;i<=n;i++) qread(a[i]);
T.build(1,n,1);
qread(m);
for(int i=1;i<=m;i++){
qread(op);
if(op==0){
qread(x);
qread(val);
T.update_point(x,val,1);
}else{
qread(l);
qread(r);
qread(k);
qprint(solve(l,r,k));
putchar('\n');
}
}
}

[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. ant-design如果按需加载组件

    Ant Design React按需加载 Ant Design是阿里巴巴为React做出的组件库,有统一的样式及一致的用户体验 官网地址:https://ant.design 1.安装: npm in ...

  2. Docker实战部署应用——Tomcat

    Tomcat 部署 拉取tomcat镜像 docker pull tomcat:8 创建tomcat容器 创建tomcat容器用于 Web应用,并且进行目录映射 docker run -id --na ...

  3. 使用Jmeter聚合报告生成对比图表

    背景 最近在帮别的项目组执行性能测试,使用的工具是Jmeter.接口录制和参数化前一个人已经做好了,我主要的工作就是执行脚本,撰写测试报告.事情并不复杂,可做起来却极为耗时. 首先,由于有6组账号,分 ...

  4. ACM-ICPC 2015 Changchun Preliminary Contest J. Unknown Treasure (卢卡斯定理+中国剩余定理)

    题目链接:https://nanti.jisuanke.com/t/A1842 题目大意:给定整数n,m,k,其中1≤m≤n≤1018,k≤10, 然后给出k个素数,保证M=p[1]*p[2]……*p ...

  5. k8s源码编译

    1.可在github上面直接下载源码 2.下载所需要的docker镜像,并打上tag,不知道tag,可以先编译一下,会提示所需image. docker pull index.alauda.cn/xu ...

  6. ATM机取款过程

    假设一个简单的ATM机的取款过程是这样的:首先提示用户输入密码,最多只能输入三次,超过3次则提示用户“密码错误,请取卡”结束交易.如果用户密码正确,再提示用户输入取款金额,ATM机只能输出100元的纸 ...

  7. Linux g++ 编译添加 pthread

    If you are going to compile a C program with pthread.h in LINUX using GCC or G++ you will have to us ...

  8. error: call of overloaded ‘sqrt(double&)’ is ambiguous

    OpenFOAM定义了新的sqrt,当引入新的Library时,必须显式地使用std::sqrt(),否则会报如下错误: error: call of overloaded 'sqrt(double& ...

  9. B1001. 害死人不偿命的(3n + 1)猜想

    题目描述 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n + 1)砍掉一半.这样一直反复砍下去,最后一定在某一步得到n=1.卡拉兹在19 ...

  10. python学习笔记(八)函数return多个值,列表推导式和交换两个变量的值

    函数return多个值: 补充知识点:写代码得到时候少用全局变量: 1.不安全 2.会一直占着内存不释放 函数多个return值,那么会把这几个return的值都放在一个元组里面,然后返回 def h ...