题目描述:
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3638
数据较小时,考虑费用流。为什么我没想到(雾)。
由于本题n较大,所以考虑进行人工增广。
用线段树维护区间最大子串,每次增广将其取反即可。
本题有4倍经验!!!
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#define N 100010
using namespace std;
int n,m,ans,tot,s[N];
struct info{int sum,ml,mr,num,pl,pr,l,r;}q[22];
struct node{int tag;info minn,maxn;}t[N*4];
class seg_tree
{
void change(int x)
{
t[x].tag^=1;swap(t[x].maxn,t[x].minn);
}
void pushdown(int x)
{
if(!t[x].tag)return;
int lc=x<<1,rc=lc+1;t[x].tag=0;
change(lc);change(rc);
}
info merge(info a,info b)
{
info res;res.sum=a.sum+b.sum;
res.ml=a.ml;res.mr=b.mr;
res.pl=a.pl;res.pr=b.pr;
if(a.sum+b.ml>res.ml)
res.ml=a.sum+b.ml,res.pl=b.pl;
if(b.sum+a.mr>res.mr)
res.mr=b.sum+a.mr,res.pr=a.pr;
res.num=a.mr+b.ml;res.l=a.pr;res.r=b.pl;
if(a.num>res.num)
res.num=a.num,res.l=a.l,res.r=a.r;
if(b.num>res.num)
res.num=b.num,res.l=b.l,res.r=b.r;
return res;
}
void update(int x)
{
int lc=x<<1,rc=lc+1;
t[x].maxn=merge(t[lc].maxn,t[rc].maxn);
t[x].minn=merge(t[lc].minn,t[rc].minn);
}
public:
void build(int x,int l,int r)
{
t[x].tag=0;
if(l==r)
{
info res;
res.sum=res.num=res.ml=res.mr=s[l];
res.l=res.r=res.pl=res.pr=l;
t[x].maxn=res;
res.sum=res.num=res.ml=res.mr=-s[l];
t[x].minn=res;
return;
}
int mid=l+r>>1,lc=x<<1,rc=lc+1;
build(lc,l,mid);build(rc,mid+1,r);
update(x);
}
void modify(int x,int l,int r,int des,int val)
{
if(l==r)
{
info res;
res.sum=res.num=res.ml=res.mr=val;
res.l=res.r=res.pl=res.pr=l;
t[x].maxn=res;
res.sum=res.num=res.ml=res.mr=-val;
t[x].minn=res;
return;
}
int mid=l+r>>1,lc=x<<1,rc=lc+1;
pushdown(x);
if(des<=mid)modify(lc,l,mid,des,val);
else modify(rc,mid+1,r,des,val);
update(x);
}
void reverse(int x,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr){change(x);return;}
int mid=l+r>>1,lc=x<<1,rc=lc+1;
pushdown(x);
if(ql<=mid)reverse(lc,l,mid,ql,qr);
if(qr>mid)reverse(rc,mid+1,r,ql,qr);
update(x);
}
info qry(int x,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return t[x].maxn;
int mid=l+r>>1,lc=x<<1,rc=lc+1;
pushdown(x);
if(qr<=mid)return qry(lc,l,mid,ql,qr); if(ql>mid)return qry(rc,mid+1,r,ql,qr);
return merge(qry(lc,l,mid,ql,qr),qry(rc,mid+1,r,ql,qr));
}
}T;
int main()
{
int tp,x,y,k;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
T.build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&tp,&x,&y);
if(tp==1)
{
scanf("%d",&k);ans=0;tot=0;
while(k--)
{
info p=T.qry(1,1,n,x,y);
if(p.num<0)break;
T.reverse(1,1,n,p.l,p.r);
ans+=p.num;q[++tot]=p;
}
for(int i=1;i<=tot;i++)
T.reverse(1,1,n,q[i].l,q[i].r);
printf("%d\n",ans);
}
else T.modify(1,1,n,x,y);
}
return 0;
}