2021.12.08 最大连续字段和(线段树)
1. 如何求最大连续字段和
对于两个要合并的区间 \(A\) 和区间 \(B\) 。
设 \(maxn_X\) 为区间 \(X\) 的最大连续字段和, \(lmaxn_X\) 、 \(rmaxn_X\) 分别是从左端点开始最大连续字段和、从右端点开始最大连续字段和。\(maxnl_X\) 、 \(maxnr_X\) 为最大连续字段和在区间内能到达的最远的左端点、最远的右端点。\(lmaxnr_X\) 、 \(rmaxnl_X\) 是左端点最大的字段和的最远的右端点、右端点最大的字段和的左端点。
如果区间 \(A\) 的 \(lmaxn_X\) 能和 \(B\) 的 \(lmaxn_B\) 连着,那么合并起来就是新区间的从左端点开始的最大区间连续字段和。对于右端点亦然。
求新区间最大连续字段和只需要比较 \(A\) 和 \(B\) 的最大区间连续字段和和 \(rmaxn_A+lmaxn_B\) 就行。
2. 模板题
https://www.luogu.com.cn/problem/P2572
注意取反!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ls (x<<1)
#define rs (x<<1)|1
using namespace std;
const int N=1e5+10;
int n,m,val[N];
struct node{
int l,r,sum,len,lazy;
int flagl,flagr;
int maxn[2],lmaxn[2],rmaxn[2];
}t[N<<3];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline node update(node a,node b,int x){
node tmp=t[x];
tmp.sum=a.sum+b.sum;
tmp.flagl=a.flagl;tmp.flagr=b.flagr;
for(int i=0;i<2;i++){
if(a.lmaxn[i]==a.len)tmp.lmaxn[i]=a.len+b.lmaxn[i];
else tmp.lmaxn[i]=a.lmaxn[i];
if(b.rmaxn[i]==b.len)tmp.rmaxn[i]=b.len+a.rmaxn[i];
else tmp.rmaxn[i]=b.rmaxn[i];
tmp.maxn[i]=max(a.rmaxn[i]+b.lmaxn[i],max(a.maxn[i],b.maxn[i]));
}
return tmp;
}
inline void pre_pushdown0(int x){
t[x].flagl=t[x].flagr=0;t[x].sum=0;
t[x].maxn[0]=t[x].lmaxn[0]=t[x].rmaxn[0]=t[x].len;
t[x].maxn[1]=t[x].lmaxn[1]=t[x].rmaxn[1]=0;
}
inline void pre_pushdown1(int x){
t[x].flagl=t[x].flagr=1;t[x].sum=t[x].len;
t[x].maxn[0]=t[x].lmaxn[0]=t[x].rmaxn[0]=0;
t[x].maxn[1]=t[x].lmaxn[1]=t[x].rmaxn[1]=t[x].len;
}
inline void pre_pushdown2(int x){
t[x].sum=t[x].len-t[x].sum;
if(t[x].flagl==0)t[x].lmaxn[1]=t[x].lmaxn[0],t[x].lmaxn[0]=0;
else t[x].lmaxn[0]=t[x].lmaxn[1],t[x].lmaxn[1]=0;
if(t[x].flagr==0)t[x].rmaxn[1]=t[x].rmaxn[0],t[x].rmaxn[0]=0;
else t[x].rmaxn[0]=t[x].rmaxn[1],t[x].rmaxn[1]=0;
t[x].flagl^=1;t[x].flagr^=1;
swap(t[x].maxn[0],t[x].maxn[1]);
}
inline void pushdown(int x){
if(t[x].lazy==-1)return ;
if(t[x].lazy==0)pre_pushdown0(ls),pre_pushdown0(rs);
else if(t[x].lazy==1)pre_pushdown1(ls),pre_pushdown1(rs);
else if(t[x].lazy==2){
if(t[ls].lazy==-1)t[ls].lazy=2,pre_pushdown2(ls);
else if(t[ls].lazy==0)t[ls].lazy=1,pre_pushdown1(ls);
else if(t[ls].lazy==1)t[ls].lazy=0,pre_pushdown0(ls);
else if(t[ls].lazy==2)t[ls].lazy=-1,pre_pushdown2(ls);
if(t[rs].lazy==-1)t[rs].lazy=2,pre_pushdown2(rs);
else if(t[rs].lazy==0)t[rs].lazy=1,pre_pushdown1(rs);
else if(t[rs].lazy==1)t[rs].lazy=0,pre_pushdown0(rs);
else if(t[rs].lazy==2)t[rs].lazy=-1,pre_pushdown2(rs);
}
if(t[x].lazy!=2)t[ls].lazy=t[rs].lazy=t[x].lazy;
t[x].lazy=-1;
}
inline void build(int x,int l,int r){
t[x].l=l;t[x].r=r;t[x].len=r-l+1;t[x].lazy=-1;
if(l==r){
t[x].sum=val[l];
if(val[l]==1)
t[x].flagl=t[x].flagr=t[x].maxn[1]=t[x].lmaxn[1]=t[x].rmaxn[1]=1;
else
t[x].flagl=t[x].flagr=0,t[x].maxn[0]=t[x].lmaxn[0]=t[x].rmaxn[0]=1;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
t[x]=update(t[ls],t[rs],x);
}
inline int querysum(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return t[x].sum;
pushdown(x);
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=querysum(ls,l,mid,L,R);
if(R>mid)ans+=querysum(rs,mid+1,r,L,R);
t[x]=update(t[ls],t[rs],x);
return ans;
}
inline node querymax(int x,int l,int r,int L,int R){
if(l>=L&&r<=R)return t[x];
pushdown(x);
int mid=(l+r)>>1;
int flaga=0,flagb=0;
node a,b,tmp;
if(L<=mid)a=querymax(ls,l,mid,L,R),flaga=1;
if(R>mid)b=querymax(rs,mid+1,r,L,R),flagb=1;
if(flaga&&!flagb)tmp=a;
else if(flagb&&!flaga)tmp=b;
else if(flaga&&flagb)tmp=update(a,b,x);
return tmp;
}
inline void change(int x,int l,int r,int L,int R,int flag){
if(l>R||r<L)return ;
if(l>=L&&r<=R){
if(flag!=2){
t[x].lazy=flag;
if(t[x].lazy==0)pre_pushdown0(x);
else if(t[x].lazy==1)pre_pushdown1(x);
}
else if(t[x].lazy==2&&flag==2)t[x].lazy=-1,pre_pushdown2(x);//
else if(t[x].lazy==-1&&flag==2)t[x].lazy=2,pre_pushdown2(x);
else if(t[x].lazy==0&&flag==2)t[x].lazy=1,pre_pushdown1(x);
else if(t[x].lazy==1&&flag==2)t[x].lazy=0,pre_pushdown0(x);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)change(ls,l,mid,L,R,flag);
if(R>mid)change(rs,mid+1,r,L,R,flag);
t[x]=update(t[ls],t[rs],x);
}
inline void find(){
/*for(int i=1;i<=25;i++)
cout<<i<<" l "<<t[i].l<<" r "<<t[i].r<<" len "<<t[i].len
<<" sum "<<t[i].sum<<" lazy "<<t[i].lazy
<<" maxn[0] "<<t[i].maxn[0]<<" lmaxn[0] "<<t[i].lmaxn[0]<<" rmaxn[0] "<<t[i].rmaxn[0]
<<" maxn[1] "<<t[i].maxn[1]<<" lmaxn[1] "<<t[i].lmaxn[1]<<" rmaxn[1] "<<t[i].rmaxn[1]
<<" flagl "<<t[i].flagl<<" flagr "<<t[i].flagr<<endl;
cout<<endl;*/
for(int i=1;i<=n;i++)cout<<querysum(1,1,n,i,i)<<" ";
cout<<endl;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)val[i]=read();
build(1,1,n);
//find();//
for(int i=1;i<=m;i++){
int op,l,r;
op=read();l=read()+1;r=read()+1;
if(op==0)change(1,1,n,l,r,0);
else if(op==1)change(1,1,n,l,r,1);
else if(op==2)change(1,1,n,l,r,2);
else if(op==3)cout<<querysum(1,1,n,l,r)<<endl;
else if(op==4){
node tmp=querymax(1,1,n,l,r);
cout<<tmp.maxn[1]<<endl;
}
//find();//
}
return 0;
}
https://www.luogu.com.cn/problem/UVA1400
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define int long long
const int N=5e5+10;
int n,m,cnt,a[N];
int start,ans;
struct node{
int ls,rs,lsum,rsum,sum,maxn;
int lmaxn,rmaxn,rlsum,lrsum;
}t[N<<2];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
node merge(node a,node b,int pos){
node tmp;
tmp.ls=t[pos].ls;tmp.rs=t[pos].rs;
tmp.lsum=tmp.rsum=tmp.maxn=0;
tmp.sum=a.sum+b.sum;
if(a.sum+b.lsum>a.lsum){
tmp.lsum=a.sum+b.lsum;
tmp.rlsum=b.rlsum;
}else{
tmp.lsum=a.lsum;
tmp.rlsum=a.rlsum;
}
if(a.rsum+b.sum>=b.rsum){
tmp.rsum=a.rsum+b.sum;
tmp.lrsum=a.lrsum;
}else{
tmp.rsum=b.rsum;
tmp.lrsum=b.lrsum;
}
if(a.maxn>=a.rsum+b.lsum&&a.maxn>=b.maxn){
tmp.maxn=a.maxn;
tmp.lmaxn=a.lmaxn;
tmp.rmaxn=a.rmaxn;
}else if(a.rsum+b.lsum>=a.maxn&&a.rsum+b.lsum>=b.maxn){
tmp.maxn=a.rsum+b.lsum;
tmp.lmaxn=a.lrsum;
tmp.rmaxn=b.rlsum;
}else{
tmp.maxn=b.maxn;
tmp.lmaxn=b.lmaxn;
tmp.rmaxn=b.rmaxn;
}
return tmp;
}
void biuld(int x,int l,int r){
t[x].ls=l;t[x].rs=r;
if(l==r){
t[x].sum=a[l];
t[x].maxn=t[x].lsum=t[x].rsum=a[l];
t[x].lmaxn=t[x].rmaxn=t[x].rlsum=t[x].lrsum=l;
return ;
}
int mid=(l+r)>>1;
biuld(x<<1,l,mid);biuld(x<<1|1,mid+1,r);
t[x]=merge(t[x<<1],t[x<<1|1],x);
}
node query(int x,int l,int r,int li,int ri){
//if(l>ri||r<li)return (nodei){0,0,-1};
if(l>=li&&r<=ri)return t[x];
int mid=(l+r)>>1;
node tmp,a,b;
int flaga=0,flagb=0;
if(t[x<<1].rs>=li)a=query(x<<1,l,mid,li,ri),flaga=1;
if(t[x<<1|1].ls<=ri)b=query(x<<1|1,mid+1,r,li,ri),flagb=1;
if(flaga&&!flagb)tmp=a;
else if(!flaga&&flagb)tmp=b;
else if(flaga&&flagb)tmp=merge(a,b,x);
return tmp;
}
signed main(){
//freopen("1.in","r",stdin);
//freopen("2.out","w",stdout);
while(~scanf("%lld%lld",&n,&m)){
++cnt;
printf("Case %lld:\n",cnt);
memset(a,0,sizeof(a));
memset(&t,0,sizeof(t));
for(int i=1;i<=n;i++)a[i]=read();
biuld(1,1,n);
for(int i=1;i<=m;i++){
int u,v;
u=read();v=read();
node tmp=query(1,1,n,u,v);
cout<<tmp.lmaxn<<" "<<tmp.rmaxn<<endl;
}
}
return 0;
}
https://www.luogu.com.cn/problem/P4513
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=5e5+10;
const int inf=0x3f3f3f3f;
int n,m,val[N];
struct node{
int maxn,lmaxn,rmaxn,tot,ls,rs;
int maxnl,maxnr,lmaxnr,rmaxnl;
}t[N<<3];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline node update(node a,node b,int x){
node tmp;
tmp.ls=t[x].ls,tmp.rs=t[x].rs;
tmp.lmaxn=tmp.rmaxn=tmp.maxn=0;
tmp.tot=a.tot+b.tot;
if(a.tot+b.lmaxn>a.lmaxn)tmp.lmaxn=a.tot+b.lmaxn,tmp.lmaxnr=b.lmaxnr;
else tmp.lmaxn=a.lmaxn,tmp.lmaxnr=a.lmaxnr;
if(b.tot+a.rmaxn>b.rmaxn)tmp.rmaxn=b.tot+a.rmaxn,tmp.rmaxnl=a.rmaxnl;
else tmp.rmaxn=b.rmaxn,tmp.rmaxnl=b.rmaxnl;
if(a.rmaxn+b.lmaxn>=a.maxn&&a.rmaxn+b.lmaxn>=b.maxn)
tmp.maxn=a.rmaxn+b.lmaxn,tmp.maxnl=a.rmaxnl,tmp.maxnr=b.lmaxnr;
else if(a.maxn>=a.rmaxn+b.lmaxn&&a.maxn>=b.maxn)
tmp.maxn=a.maxn,tmp.maxnl=a.maxnl,tmp.maxnr=a.maxnr;
else if(b.maxn>=a.rmaxn+b.lmaxn&&b.maxn>=a.maxn)
tmp.maxn=b.maxn,tmp.maxnl=b.maxnl,tmp.maxnr=b.maxnr;
return tmp;
}
inline void build(int x,int l,int r){
t[x].ls=l;t[x].rs=r;
if(l==r){
t[x].tot=t[x].maxn=t[x].lmaxn=t[x].rmaxn=val[l];
t[x].lmaxnr=t[x].rmaxnl=t[x].maxnl=t[x].maxnr=l;
return ;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
t[x]=update(t[x<<1],t[x<<1|1],x);
}
inline void change(int x,int l,int r,int pos,int k){
if(l>pos||r<pos)return ;
if(l==r){
t[x].tot=t[x].maxn=t[x].lmaxn=t[x].rmaxn=k;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)change(x<<1,l,mid,pos,k);
if(pos>mid)change(x<<1|1,mid+1,r,pos,k);
t[x]=update(t[x<<1],t[x<<1|1],x);
}
inline node query(int x,int l,int r,int L,int R){
if(l>=L&&r<=R)return t[x];
int mid=(l+r)>>1;
node a,b,tmp;
int flaga=0,flagb=0;
if(L<=mid)a=query(x<<1,l,mid,L,R),flaga=1;
if(R>mid)b=query(x<<1|1,mid+1,r,L,R),flagb=1;
if(flaga&&!flagb)tmp=a;
else if(!flaga&&flagb)tmp=b;
else if(flaga&&flagb)tmp=update(a,b,x);
return tmp;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)val[i]=read();
build(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y;
op=read();x=read();y=read();
if(op==1){
if(x>y)swap(x,y);
//cout<<x<<" "<<y<<endl;
node ans=query(1,1,n,x,y);
cout<<ans.maxn<<endl;
}else if(op==2)change(1,1,n,x,y);
}
return 0;
}
https://www.luogu.com.cn/problem/P4344
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int n,m;
struct node{
int l,r,sum,lazy,len;
int maxn,rmaxn,lmaxn;
}t[N<<3];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline node update(node a,node b,int x){
node tmp;
tmp.sum=a.sum+b.sum;
tmp.l=t[x].l;tmp.r=t[x].r;tmp.len=t[x].len;tmp.lazy=t[x].lazy;
if(a.lmaxn==a.len)tmp.lmaxn=a.len+b.lmaxn;
else tmp.lmaxn=a.lmaxn;
if(b.rmaxn==b.len)tmp.rmaxn=b.len+a.rmaxn;
else tmp.rmaxn=b.rmaxn;
tmp.maxn=max(a.rmaxn+b.lmaxn,max(a.maxn,b.maxn));
return tmp;
}
inline void pushdown(int x){
if(!t[x].lazy)return ;
t[x<<1].lazy=t[x<<1|1].lazy=t[x].lazy;
if(t[x].lazy==1){
t[x<<1].sum=t[x<<1].len;
t[x<<1].lmaxn=t[x<<1].rmaxn=t[x<<1].maxn=0;
t[x<<1|1].sum=t[x<<1|1].len;
t[x<<1|1].lmaxn=t[x<<1|1].rmaxn=t[x<<1|1].maxn=0;
}else if(t[x].lazy==-1){
t[x<<1].sum=0;
t[x<<1].lmaxn=t[x<<1].rmaxn=t[x<<1].maxn=t[x<<1].len;
t[x<<1|1].sum=0;
t[x<<1|1].lmaxn=t[x<<1|1].rmaxn=t[x<<1|1].maxn=t[x<<1|1].len;
}
t[x].lazy=0;
}
inline void build(int x,int l,int r){
t[x].l=l;t[x].r=r;t[x].lazy=0;
t[x].maxn=t[x].lmaxn=t[x].rmaxn=0;
t[x].len=r-l+1;
if(l==r)return (void)(t[x].sum=1,t[x].maxn=t[x].lmaxn=t[x].rmaxn=0);
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
t[x]=update(t[x<<1],t[x<<1|1],x);
}
inline int query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return t[x].sum;
pushdown(x);
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=query(x<<1,l,mid,L,R);
if(R>mid)ans+=query(x<<1|1,mid+1,r,L,R);
//t[x]=update(t[x<<1],t[x<<1|1],x);//
return ans;
}
inline node querymax(int x,int l,int r,int L,int R){
if(l>=L&&r<=R)return t[x];
pushdown(x);
int mid=(l+r)>>1;
node a,b,tmp;
int flaga=0,flagb=0;
if(L<=mid)a=querymax(x<<1,l,mid,L,R),flaga=1;
if(R>mid)b=querymax(x<<1|1,mid+1,r,L,R),flagb=1;
if(flaga&&!flagb)tmp=a;
else if(flagb&&!flaga)tmp=b;
else if(flaga&&flagb)tmp=update(a,b,x);
//t[x]=update(t[x<<1],t[x<<1|1],x);//
return tmp;
}
inline int queryzero(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return t[x].len-t[x].sum;
pushdown(x);
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=queryzero(x<<1,l,mid,L,R);
if(R>mid)ans+=queryzero(x<<1|1,mid+1,r,L,R);
//t[x]=update(t[x<<1],t[x<<1|1],x);//
return ans;
}
inline void change(int x,int l,int r,int L,int R,int flag){
if(l>R||r<L)return ;
if(l>=L&&r<=R){
t[x].lazy=flag;
if(flag==1)t[x].sum=t[x].len,t[x].lmaxn=t[x].rmaxn=t[x].maxn=0;
else if(flag==-1)t[x].sum=0,t[x].lmaxn=t[x].rmaxn=t[x].maxn=t[x].len;
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)change(x<<1,l,mid,L,R,flag);
if(R>mid)change(x<<1|1,mid+1,r,L,R,flag);
t[x]=update(t[x<<1],t[x<<1|1],x);
}
inline int find(int x,int l,int r){
int L=l-1,R=r+1,mid,ans=0;
while(L+1<R){
mid=(L+R)>>1;
//cout<<"l "<<l<<" r "<<mid<<" query "<<queryzero(1,1,n,l,mid)<<endl;//
if(queryzero(1,1,n,l,mid)<=x)ans=mid,L=mid;
else R=mid;
}
//cout<<"l "<<l<<" r "<<r<<" ans "<<ans<<endl;
return ans;
}
inline void op1(int l,int r){
change(1,1,n,l,r,-1);
}
inline void op2(int l,int r,int L,int R){
int tot=query(1,1,n,l,r);
//int toti=queryzero(1,1,n,L,R);
//cout<<"tot "<<tot<<" toti "<<toti<<endl;//
//tot=min(tot,toti);
if(tot==0)return ;
change(1,1,n,l,r,-1);
int x=find(tot,L,R);
//cout<<" tot "<<tot<<" pos L "<<L<<" R "<<x<<endl;//
change(1,1,n,L,x,1);
}
inline void op3(int l,int r){
node tmp=querymax(1,1,n,l,r);
cout<<tmp.maxn<<endl;
}
int main(){
//freopen("brainhole3.in","r",stdin);
//freopen("brainhole.out","w",stdout);
n=read();m=read();
build(1,1,n);
for(int i=1;i<=m;i++){
int op=read();
if(op==0){
int u,v;
u=read();v=read();
op1(u,v);
}else if(op==1){
int x,y,u,v;
x=read();y=read();u=read();v=read();
op2(x,y,u,v);
}else if(op==2){
int u,v;
u=read();v=read();
op3(u,v);
}
/*for(int j=1;j<=25;j++)
cout<<j<<" l "<<t[j].l<<" r "<<t[j].r<<" len "<<t[j].len<<" sum "<<t[j].sum<<" maxn "<<t[j].maxn<<" lmaxn "<<t[j].lmaxn<<" rmaxn "<<t[j].rmaxn<<" lazy "<<t[j].lazy<<endl;
cout<<endl;*/
}
return 0;
}