Description
给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少。
N,M<=100000 ,1<=k<=20.l<=l<=r<=n.数值的绝对值不会超过500.
可以不选
Solution
线段树模拟费用流,好像也可以看成是可撤销的贪心
考虑怎么做单次询问,一个显然的做法就是我们把位置拆点然后跑费用流,然后我就不会了
可以发现我们在最短路增广的时候等价于选出一段最大连续和,并将这一段取反,那么线段树就可以了。要维护的东西有点多,想清楚了写比较好
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int INF=0x3f3f3f3f;
const int N=200005;
struct pos {int l,r;} ;
struct data {
int ls,rs,mx,sum;
pos p,q;
void init(int x,int v) {
ls=rs=mx=sum=v;
p=q=(pos) {x,x};
}
} ;
struct treeNode {
data mx,mn;
void rev() {std:: swap(mx,mn);}
} t[N<<2];
int tag[N<<2],n;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
data merge(data a,data b) {
data res; res.init(0,0);
res.sum=a.sum+b.sum;
if (a.mx>res.mx) {res.mx=a.mx,res.p=a.p;};
if (b.mx>res.mx) {res.mx=b.mx,res.p=b.p;};
if (a.rs+b.ls>res.mx) {
res.mx=a.rs+b.ls;
res.p=(pos) {a.q.r,b.q.l};
}
if (a.sum+b.ls>a.ls) {
res.ls=a.sum+b.ls; res.q.l=b.q.l;
} else {
res.ls=a.ls; res.q.l=a.q.l;
}
if (b.sum+a.rs>b.rs) {
res.rs=b.sum+a.rs; res.q.r=a.q.r;
} else {
res.rs=b.rs; res.q.r=b.q.r;
}
return res;
}
void push_down(int now) {
if (!tag[now]) return ;
t[now<<1].rev(); t[now<<1|1].rev();
tag[now<<1]^=1; tag[now<<1|1]^=1;
tag[now]=0;
}
void push_up(int now) {
t[now].mn=merge(t[now<<1].mn,t[now<<1|1].mn);
t[now].mx=merge(t[now<<1].mx,t[now<<1|1].mx);
}
void modify(int now,int tl,int tr,int l,int r) {
if (r<l) return ;
if (tl>=l&&tr<=r) {
t[now].rev();
tag[now]^=1;
return ;
}
push_down(now);
int mid=(tl+tr)>>1;
modify(now<<1,tl,mid,l,std:: min(r,mid));
modify(now<<1|1,mid+1,tr,std:: max(mid+1,l),r);
push_up(now);
}
void change(int now,int tl,int tr,int x,int v) {
if (tl==tr) {
t[now].mx.init(tl,v);
t[now].mn.init(tl,-v);
return ;
}
int mid=(tl+tr)>>1;
if (x<=mid) change(now<<1,tl,mid,x,v);
else change(now<<1|1,mid+1,tr,x,v);
push_up(now);
}
data query(int now,int tl,int tr,int l,int r) {
if (tl>=l&&tr<=r) return t[now].mx;
push_down(now);
int mid=(tl+tr)>>1;
if (r<=mid) return query(now<<1,tl,mid,l,r);
if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
data qx=query(now<<1,tl,mid,l,mid);
data qy=query(now<<1|1,mid+1,tr,mid+1,r);
return merge(qx,qy);
}
void build_tree(int now,int tl,int tr) {
if (tl==tr) {
int x=read();
t[now].mx.init(tl,x);
t[now].mn.init(tl,-x);
return ;
}
int mid=(tl+tr)>>1;
build_tree(now<<1,tl,mid);
build_tree(now<<1|1,mid+1,tr);
push_up(now);
}
void solve(int l,int r,int k) {
std:: vector <pair> vec;
int ans=0;
for (;k--;) {
data res=query(1,1,n,l,r);
if (res.mx>0) {
ans+=res.mx;
modify(1,1,n,res.p.l,res.p.r);
vec.push_back(pair(res.p.l,res.p.r));
}
}
for (int i=0;i<vec.size();++i) {
pair now=vec[i];
modify(1,1,n,now.fi,now.se);
}
printf("%d\n", ans);
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
n=read();
build_tree(1,1,n);
for (int m=read();m--;) {
int opt=read(),l=read(),r=read();
if (opt==1) {
int x=read();
solve(l,r,x);
} else change(1,1,n,l,r);
}
return 0;
}