【题目】
LOJ
有两所学校,第一所学校有
n
n
n门课程,编号分别是
a
1
,
…
,
a
n
a_1,\dots ,a_n
a1,…,an,课程质量
x
i
x_i
xi。第二所学校有
m
m
m门课程,编号分别是
b
1
,
…
,
b
m
b_1,\dots,b_m
b1,…,bm,课程质量
y
i
y_i
yi。两所学校开设课程编号可能相同。
现在可以在分别学校学习连续一段课程,比如
a
l
,
a
l
+
1
,
…
,
a
r
a_{l},a_{l+1},\dots, a_{r}
al,al+1,…,ar,但需要满足在两所学校选择课程编号不同。求最大课程质量和。
n , m ≤ 5 × 1 0 5 n,m\leq 5\times 10^5 n,m≤5×105
【解题思路】
如果只上一所学校课程,显然会选择这所学校所有课程,因此至少有一所学校选择的课程权值超过这所学校总权值一半。
假设现在第一所学校一定要超过一半,那么设第一所学校第一次前缀和超过总权值一半的位置为 p p p,则这个位置一定要被选择。
那么答案就是在第二所学校的课程中旋任意一段,然后将重复的课程在第一所学校的课表中标记出来,从 p p p开始往两边尽可能拓展。
枚举第二所学校所选择的右端点,那么每次至多一个位置不能被选择,不妨用两个单调栈维护当前每个 l l l到当前的 r r r的区间,在第一所学校选择的左右端点分别是什么,可以用线段树维护被影响的区间贡献。
复杂度 O ( n log n ) O(n\log n) O(nlogn)
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
namespace DreamLolita
{
int n,m,topl,topr,p1,p2,p3,p4,fg;
int a[N],b[N],c[N<<1],sl[N],sr[N];
ll ans,suma[N],sumb[N];
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
ll mx[N<<2],tar[N<<2];
void build(int x,int l,int r)
{
tar[x]=0;
if(l==r){mx[x]=suma[n]-sumb[l-1];return;}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
mx[x]=max(mx[ls],mx[rs])+tar[x];
}
void update(int x,int l,int r,int L,int R,ll v)
{
if(L<=l && r<=R){mx[x]+=v;tar[x]+=v;return;}
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,v);
if(R>mid) update(rs,mid+1,r,L,R,v);
mx[x]=max(mx[ls],mx[rs])+tar[x];
}
int query(int x,int l,int r)
{
if(l==r) return l;
int mid=(l+r)>>1;
if(mx[x]==mx[ls]+tar[x]) return query(ls,l,mid);
else return query(rs,mid+1,r);
}
#undef ls
#undef rs
}T;
void updateans(ll v,int a,int b,int c,int d)
{
if(fg) swap(a,c),swap(b,d);
if(v>ans) ans=v,p1=a,p2=b,p3=c,p4=d;
}
void solve()
{
int mid=lower_bound(suma+1,suma+n+1,(suma[n]+1)/2)-suma;
T.build(1,1,m);topl=topr=0;
for(int i=1;i<=m;++i)
{
if(b[i])
{
if(b[i]<=mid)
{
while(topl && b[i]>b[sl[topl]]) T.update(1,1,m,sl[topl-1]+1,sl[topl],suma[b[sl[topl]]]),--topl;
T.update(1,1,m,sl[topl]+1,i,-suma[b[i]]);sl[++topl]=i;
}
else
{
while(topr && b[i]<b[sr[topr]]) T.update(1,1,m,sr[topr-1]+1,sr[topr],suma[n]-suma[b[sr[topr]]-1]),--topr;
T.update(1,1,m,sr[topr]+1,i,suma[b[i]-1]-suma[n]);sr[++topr]=i;
}
}
int j=T.query(1,1,m);
int pl=lower_bound(sl+1,sl+topl+1,j)-sl,pr=lower_bound(sr+1,sr+topr+1,j)-sr;
pl=(pl<=topl?b[sl[pl]]+1:1);pr=(pr<=topr?b[sr[pr]]-1:n);
updateans(sumb[i]+T.mx[1],pl,pr,j,i);
}
}
void solution()
{
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) suma[i]=suma[i-1]+read();
for(int i=1;i<=m;++i) c[read()]=i;
for(int i=1;i<=m;++i) sumb[i]=sumb[i-1]+read();
for(int i=1;i<=n;++i) a[i]=c[a[i]],b[a[i]]=i;
updateans(suma[n],1,n,0,0);updateans(sumb[m],0,0,1,m);
solve();swap(n,m);swap(a,b);swap(suma,sumb);fg=1;solve();
printf("%lld\n%d %d\n%d %d\n",ans,p1,p2,p3,p4);
}
}
int main()
{
#ifdef Durant_Lee
freopen("LOJ2773.in","r",stdin);
freopen("LOJ2773.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}