因为k很小,所以很容易想到网络流….
然后想了想复杂度不对我就弃掉了.....
其实可以拿线段树模拟一下网络流的过程
在区间中贪心选出最大连续子段和,再将他们的值变成相反数,重复k次就可以了
维护的东西太多了,写起来好恶心…..
代码如下:
#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define N 1000020
using namespace std;
inline int read(){
int x=0,f=1;char c;
do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
struct Data{
int sum;
int lmax,rmax,maxx,lm,rm,p1,p2;
int lmin,rmin,minn,ln,rn,p3,p4;
inline void Rever(){
swap(lmax,lmin);swap(rmax,rmin);
swap(maxx,minn);
swap(lm,ln);swap(rm,rn);
swap(p1,p3);swap(p2,p4);
lmax*=-1;rmax*=-1;lmin*=-1;rmin*=-1;
maxx*=-1;minn*=-1;sum*=-1;
}
}tmp,t;
int a[N];
int n,m,k,l,r,opt,top,ans;
inline Data Merge(Data a,Data b){
tmp.sum=a.sum+b.sum;
if(a.lmax<a.sum+b.lmax) tmp.lmax=a.sum+b.lmax,tmp.lm=b.lm;
else tmp.lmax=a.lmax,tmp.lm=a.lm;
if(b.rmax<b.sum+a.rmax) tmp.rmax=b.sum+a.rmax,tmp.rm=a.rm;
else tmp.rmax=b.rmax,tmp.rm=b.rm;
if(a.lmin>a.sum+b.lmin) tmp.lmin=a.sum+b.lmin,tmp.ln=b.ln;
else tmp.lmin=a.lmin,tmp.ln=a.ln;
if(b.rmin>b.sum+a.rmin) tmp.rmin=b.sum+a.rmin,tmp.rn=a.rn;
else tmp.rmin=b.rmin,tmp.rn=b.rn;
if(a.rmax+b.lmax>a.maxx) tmp.maxx=a.rmax+b.lmax,tmp.p1=a.rm,tmp.p2=b.lm;
else tmp.maxx=a.maxx,tmp.p1=a.p1,tmp.p2=a.p2;
if(b.maxx>tmp.maxx) tmp.maxx=b.maxx,tmp.p1=b.p1,tmp.p2=b.p2;
if(a.rmin+b.lmin<a.minn) tmp.minn=a.rmin+b.lmin,tmp.p3=a.rn,tmp.p4=b.ln;
else tmp.minn=a.minn,tmp.p3=a.p3,tmp.p4=a.p4;
if(b.minn<tmp.minn) tmp.minn=b.minn,tmp.p3=b.p3,tmp.p4=b.p4;
return tmp;
}
struct PP{
int l,r;
PP(){}
PP(int l,int r):l(l),r(r){}
}s[N];
struct Node{
Node *ls,*rs;
bool v;
Data x;
Node():ls(NULL),rs(NULL){}
inline void maintain(){
x=Merge(ls->x,rs->x);
}
inline void pushdown(){
if(!v) return;
ls->v^=1;rs->v^=1;
ls->x.Rever();rs->x.Rever();
v=0;
}
}*root;
void build(int L,int R,Node *&k){
k=new Node;k->v=false;
if(L==R){
k->x.lmax=k->x.rmax=k->x.maxx=k->x.lmin=k->x.rmin=k->x.minn=k->x.sum=a[L];
k->x.ln=k->x.lm=k->x.rn=k->x.rm=k->x.p1=k->x.p2=k->x.p3=k->x.p4=R;
return;
}
int mid=(L+R)>>1;
build(L,mid,k->ls);build(mid+1,R,k->rs);
k->maintain();
}
Data Query(int L,int R,int x,int y,Node *k){
if(L>=x && R<=y) return k->x;
int mid=(L+R)>>1;
k->pushdown();
if(y<=mid) return Query(L,mid,x,y,k->ls);
else if(x>mid) return Query(mid+1,R,x,y,k->rs);
else return Merge(Query(L,mid,x,y,k->ls),Query(mid+1,R,x,y,k->rs));
}
void Reverse(int L,int R,int x,int y,Node *k){
if(L>=x && R<=y){
k->v^=1;
k->x.Rever();
return;
}
k->pushdown();
int mid=(L+R)>>1;
if(y<=mid) Reverse(L,mid,x,y,k->ls);
else if(x>mid) Reverse(mid+1,R,x,y,k->rs);
else Reverse(L,mid,x,y,k->ls),Reverse(mid+1,R,x,y,k->rs);
k->maintain();
}
inline void solve(int l,int r,int k){
ans=0;
while(k--){
t=Query(1,n,l,r,root);
if(t.maxx<=0) break;
ans+=t.maxx;
Reverse(1,n,t.p1,t.p2,root);
s[++top]=PP(t.p1,t.p2);
}
while(top){
Reverse(1,n,s[top].l,s[top].r,root);
top--;
}
printf("%d\n",ans);
return;
}
void Modify(int L,int R,int x,int v,Node *k){
if(L==R){
k->x.lmax=k->x.rmax=k->x.maxx=k->x.lmin=k->x.rmin=k->x.minn=k->x.sum=a[L]=v;
k->x.ln=k->x.lm=k->x.rn=k->x.rm=k->x.p1=k->x.p2=k->x.p3=k->x.p4=L;
return;
}
k->pushdown();
int mid=(L+R)>>1;
if(x<=mid) Modify(L,mid,x,v,k->ls);
else Modify(mid+1,R,x,v,k->rs);
k->maintain();
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,n,root);
m=read();
for(int i=1;i<=m;i++){
opt=read();l=read();r=read();
if(opt==1){
k=read();
solve(l,r,k);
}
else Modify(1,n,l,r,root);
}
return 0;
}