如果只上一所学校的课,那么显然要选择这所学校的所有课程。因此,至少有一所学校选择的课程权值超过了这所学校总权值的一半。不妨强制第一所学校要超过,那么设第一所学校第一次前缀和超过总权值一半的位置为 p p p,则这个位置一定要被选择。在第二所学校选择了一些课程后,一定是从 p p p开始,尽量往两边扩展。
枚举第二所学校选择的右端点 r r r,那么每次最多会有一个位置不能再被选择。可以用两个单调栈维护当前每个 l l l到当前的 r r r的区间,他们在第一所学校选择的左右端点分别是什么,这些被影响的贡献是相同的,可以用一个线段树维护。
#include
using namespace std;
#define LL long long
#define pa pair
const int Maxn=500010;
const LL inf=(1LL<<50);
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,a[Maxn],b[Maxn],A[Maxn],B[Maxn],cnt=0;
struct P{int x,id;}T[Maxn<<1];
bool cmp(P a,P b){return a.x<b.x;}
struct Seg{int l,r,lc,rc;LL p,mx,tag;}tr[Maxn<<1];
int tot=0;
void Add(int x,LL v){tr[x].tag+=v;tr[x].mx+=v;}
void up(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
if(tr[lc].mx>tr[rc].mx)tr[x].mx=tr[lc].mx,tr[x].p=tr[lc].p;
else tr[x].mx=tr[rc].mx,tr[x].p=tr[rc].p;
}
void down(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;LL t=tr[x].tag;
if(t)tr[x].tag=0,Add(lc,t),Add(rc,t);
}
void build(int l,int r)
{
int x=++tot;
tr[x].l=l;tr[x].r=r;tr[x].tag=0;tr[x].mx=0;tr[x].p=l;
if(l==r)return;
int mid=l+r>>1;
tr[x].lc=tot+1,build(l,mid);
tr[x].rc=tot+1,build(mid+1,r);
}
void add(int x,int l,int r,LL v)
{
if(tr[x].l==l&&tr[x].r==r){Add(x,v);return;}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
down(x);
if(r<=mid)add(lc,l,r,v);
else if(l>mid)add(rc,l,r,v);
else add(lc,l,mid,v),add(rc,mid+1,r,v);
up(x);
}
int L1,R1,L2,R2;LL Ans=0;
int l1,r1,l2,r2;LL ans=0;
int pos[Maxn<<1],ul[Maxn],ur[Maxn];
struct Node
{
int p,L,R;
Node(int _p=0,int _L=0,int _R=0){p=_p,L=_L,R=_R;}
};
Node sta1[Maxn],sta2[Maxn];int top1,top2;LL sum[Maxn];
int fl[Maxn];int Fl(int x){return((fl[x]==x)?x:fl[x]=Fl(fl[x]));}
int fr[Maxn];int Fr(int x){return((fr[x]==x)?x:fr[x]=Fr(fr[x]));}
void solve(int op)
{
LL s2=0;int pp;
for(int i=1;i<=cnt;i++)pos[i]=-1;
sum[0]=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i],pos[A[i]]=i;
for(int i=1;i<=m;i++)fl[i]=fr[i]=i;
ans=sum[n];l1=1,r1=n;l2=r2=0;
for(int i=1;i<=n;i++)
{
s2+=a[i];
if(s2>(sum[n]>>1)){pp=i;break;}
}
tot=0;build(1,m);top1=top2=0;
for(int r=1;r<=m;r++)
{
add(1,1,r,b[r]);
if(pos[B[r]]==-1)
{
ul[r]=1,ur[r]=n;add(1,r,r,sum[n]);
sta1[++top1]=Node(1,r,r);
sta2[++top2]=Node(n,r,r);
}
else
{
if(pos[B[r]]<pp)
{
int ll=r;int t=pos[B[r]]+1;
while(top1&&sta1[top1].p<=t)
{
LL delta=-(sum[t-1]-sum[sta1[top1].p-1]);
add(1,sta1[top1].L,sta1[top1].R,delta);
ll=sta1[top1].L;fl[sta1[top1].R]=r;
top1--;
}
ul[r]=t;ur[r]=n;add(1,r,r,sum[n]-sum[t-1]);
sta1[++top1]=Node(t,ll,r);
sta2[++top2]=Node(n,r,r);
}
else
{
int ll=r;int t=pos[B[r]]-1;
while(top2&&sta2[top2].p>=t)
{
LL delta=-(sum[sta2[top2].p]-sum[t]);
add(1,sta2[top2].L,sta2[top2].R,delta);
ll=sta2[top2].L;fr[sta2[top2].R]=r;
top2--;
}
ul[r]=1;ur[r]=t;add(1,r,r,sum[t]);
sta2[++top2]=Node(t,ll,r);
sta1[++top1]=Node(1,r,r);
}
}
if(tr[1].mx>ans)
{
ans=tr[1].mx;
l2=tr[1].p,r2=r;
l1=ul[Fl(tr[1].p)],r1=ur[Fr(tr[1].p)];
}
}
if(op)swap(l1,l2),swap(r1,r2);
if(ans>Ans)Ans=ans,L1=l1,R1=r1,L2=l2,R2=r2;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)T[i].x=read(),T[i].id=i;
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=m;i++)T[i+n].x=read(),T[i+n].id=i+n;
for(int i=1;i<=m;i++)b[i]=read();
sort(T+1,T+1+n+m,cmp);
for(int i=1;i<=n+m;i++)
{
if(i==1||T[i].x!=T[i-1].x)cnt++;
if(T[i].id<=n)A[T[i].id]=cnt;else B[T[i].id-n]=cnt;
}
solve(0);
for(int i=1;i<=max(n,m);i++)swap(a[i],b[i]),swap(A[i],B[i]);
swap(n,m);
solve(1);
if(L1>R1)L1=R1=0;if(L2>R2)L2=R2=0;
printf("%lld\n%d %d\n%d %d",Ans,L1,R1,L2,R2);
}