题目大意
给定数列{an},要求维护以下操作和询问:
∙将ai赋值为val
∙在区间[l,r]中选出最多k个互不相交的子段列,最大化这些选中的数的和,输出这个最大值
操作和询问共
1≤n≤105,1≤m≤105,|ai|≤500,|val|≤500,1≤k≤20
题目分析
先来想想大暴力怎么做询问。
我们将每个数拆成两个点A和
可以发现这个增广过程其实就是选出一段最大子段和然后全部取反。
那么我们直接使用线段树维护即可。支持操作有查询区间子段和极值和位置,区间取反,单点修改。
时间复杂度
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
const int N=100050;
const int K=25;
int rs[K][2];
int tot,n,m;
int a[N];
struct D
{
int ls[2][2],rs[2][2],ans[2][3];
bool tag;
int sum;
};
D operator+(D x,D y)
{
D ret;
ret.tag=false;
ret.sum=x.sum+y.sum;
if (x.ls[0][0]>x.sum+y.ls[0][0])
ret.ls[0][0]=x.ls[0][0],ret.ls[0][1]=x.ls[0][1];
else
ret.ls[0][0]=x.sum+y.ls[0][0],ret.ls[0][1]=y.ls[0][1];
if (x.ls[1][0]<x.sum+y.ls[1][0])
ret.ls[1][0]=x.ls[1][0],ret.ls[1][1]=x.ls[1][1];
else
ret.ls[1][0]=x.sum+y.ls[1][0],ret.ls[1][1]=y.ls[1][1];
if (y.rs[0][0]>y.sum+x.rs[0][0])
ret.rs[0][0]=y.rs[0][0],ret.rs[0][1]=y.rs[0][1];
else
ret.rs[0][0]=y.sum+x.rs[0][0],ret.rs[0][1]=x.rs[0][1];
if (y.rs[1][0]<y.sum+x.rs[1][0])
ret.rs[1][0]=y.rs[1][0],ret.rs[1][1]=y.rs[1][1];
else
ret.rs[1][0]=y.sum+x.rs[1][0],ret.rs[1][1]=x.rs[1][1];
ret.ans[0][0]=x.ans[0][0],ret.ans[0][1]=x.ans[0][1],ret.ans[0][2]=x.ans[0][2];
if (ret.ans[0][0]<y.ans[0][0])
ret.ans[0][0]=y.ans[0][0],ret.ans[0][1]=y.ans[0][1],ret.ans[0][2]=y.ans[0][2];
if (ret.ans[0][0]<x.rs[0][0]+y.ls[0][0])
ret.ans[0][0]=x.rs[0][0]+y.ls[0][0],ret.ans[0][1]=x.rs[0][1],ret.ans[0][2]=y.ls[0][1];
ret.ans[1][0]=x.ans[1][0],ret.ans[1][1]=x.ans[1][1],ret.ans[1][2]=x.ans[1][2];
if (ret.ans[1][0]>y.ans[1][0])
ret.ans[1][0]=y.ans[1][0],ret.ans[1][1]=y.ans[1][1],ret.ans[1][2]=y.ans[1][2];
if (ret.ans[1][0]>x.rs[1][0]+y.ls[1][0])
ret.ans[1][0]=x.rs[1][0]+y.ls[1][0],ret.ans[1][1]=x.rs[1][1],ret.ans[1][2]=y.ls[1][1];
return ret;
}
struct segment_tree
{
D d[N<<2];
void R(int x)
{
d[x].tag^=1;
swap(d[x].ans[0][0],d[x].ans[1][0]),swap(d[x].ans[0][1],d[x].ans[1][1]),swap(d[x].ans[0][2],d[x].ans[1][2]);
swap(d[x].ls[0][0],d[x].ls[1][0]),swap(d[x].ls[0][1],d[x].ls[1][1]);
swap(d[x].rs[0][0],d[x].rs[1][0]),swap(d[x].rs[0][1],d[x].rs[1][1]);
d[x].ans[0][0]*=-1,d[x].ans[1][0]*=-1;
d[x].ls[0][0]*=-1,d[x].ls[1][0]*=-1;
d[x].rs[0][0]*=-1,d[x].rs[1][0]*=-1;
d[x].sum*=-1;
}
void clear(int x,int l,int r)
{
if (l==r)
return;
if (d[x].tag)
{
R(x<<1),R(x<<1|1);
d[x].tag=false;
}
}
void update(int x)
{
bool rec=d[x].tag;
d[x]=d[x<<1]+d[x<<1|1];
d[x].tag=rec;
}
void build(int x,int l,int r)
{
if (l==r)
{
d[x].sum=d[x].ls[0][0]=d[x].ls[1][0]=d[x].rs[0][0]=d[x].rs[1][0]=d[x].ans[0][0]=d[x].ans[1][0]=a[l];
d[x].ls[0][1]=d[x].ls[1][1]=d[x].rs[0][1]=d[x].rs[1][1]=d[x].ans[0][1]=d[x].ans[0][2]=d[x].ans[1][1]=d[x].ans[1][2]=l;
d[x].tag=false;
return;
}
int mid=l+r>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
update(x);
}
D query(int x,int st,int en,int l,int r)
{
clear(x,l,r);
if (st==l&&en==r)
return d[x];
int mid=l+r>>1;
if (en<=mid)
return query(x<<1,st,en,l,mid);
else
if (mid+1<=st)
return query(x<<1|1,st,en,mid+1,r);
else
return query(x<<1,st,mid,l,mid)+query(x<<1|1,mid+1,en,mid+1,r);
}
void reverse(int x,int st,int en,int l,int r)
{
clear(x,l,r);
if (st==l&&en==r)
{
R(x);
return;
}
int mid=l+r>>1;
if (en<=mid)
reverse(x<<1,st,en,l,mid);
else
if (mid+1<=st)
reverse(x<<1|1,st,en,mid+1,r);
else
reverse(x<<1,st,mid,l,mid),reverse(x<<1|1,mid+1,en,mid+1,r);
update(x);
}
void change(int x,int y,int l,int r,int edit)
{
clear(x,l,r);
if (l==r)
{
d[x].sum=d[x].ls[0][0]=d[x].ls[1][0]=d[x].rs[0][0]=d[x].rs[1][0]=d[x].ans[0][0]=d[x].ans[1][0]=a[l]=edit;
return;
}
int mid=l+r>>1;
if (y<=mid)
change(x<<1,y,l,mid,edit);
else
change(x<<1|1,y,mid+1,r,edit);
update(x);
}
}t;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch))
{
if (ch=='-')
f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main()
{
freopen("diyiti.in","r",stdin);
freopen("diyiti.out","w",stdout);
n=read();
for (int i=1;i<=n;i++)
a[i]=read();
t.build(1,1,n);
m=read();
for (int i=1;i<=m;i++)
{
int op=read();
if (!op)
{
int x=read(),y=read();
t.change(1,x,1,n,y);
}
else
{
int d=read(),r=read(),k=read();
int maxcost=0;
while (k--)
{
D get=t.query(1,d,r,1,n);
if (get.ans[0][0]<=0)
break;
rs[++tot][0]=get.ans[0][1],rs[tot][1]=get.ans[0][2];
t.reverse(1,rs[tot][0],rs[tot][1],1,n);
maxcost+=get.ans[0][0];
}
printf("%d\n",maxcost);
while (tot)
{
t.reverse(1,rs[tot][0],rs[tot][1],1,n);
tot--;
}
}
}
fclose(stdin);
fclose(stdout);
return 0;
}