[ROI 2017] 学习轨迹 (Day 2) 题解
题面
假如钦定了序列 \(b\) 中某个位置必选,则我们就可以求出另一个序列的最大禁用位置和最小禁用位置。
设前缀和数组为 \(p\),称一个序列的第一个使得 \(p_i >=p_n\) 的下标为权值中点,两个序列的权值中点必有一个会被选择,这是因为假若两个都不选,则无论怎么选,选出来的段权值之和小于总权值之和的一半,而你直接选一整个 \(a\) 序列或者 \(b\) 序列的较大值就可以取到总权值之和的一半。
所以权值中点 \(md\) 是必选的点,可以先令 \(a\) 的权值中点必选,\(b\) 只要反过来再做一遍就行了。
令 \(L_i\) 表示和 \(b_i\) 相同种类的 \(a_x\) 在 \(md\) 左侧,\(L_i=x\)。\(R_i\) 同理。
那么假如我们已经确定了序列 \(b\) 中 \([l_2,r_2]\) 要选,那么序列 \(a\) 选出的 \(l_1,r_1\) 必须满足 \(l_1>\max_{i \in [l_2,r_2]}L_i\) 且 \(r_1<\min_{i \in [l2,r2]}R_i\),贪心的考虑肯定是全部选择能令收益最大,即选择 \([\max{L_i+1},\min{R_i-1}]\)。
假如已经确定了 \(l_2,r_2\),此时总收益为 \(px_{r_2}-px_{l2-1}+py_{R_i}-py_{L_i-1}\)。我们可以枚举 \(r\),然后用单调栈维护当前的 \(L_r\) 和 \(R_r\) 在什么范围内是最大/小值,然后用线段树,每个节点维护 \(-px_{l2-1}+py_{R_i}-py_{L_i-1}\) 的值,那我们每次取其加上 \(px_r\) 最大的值和位置。
寻找另一个序列的区间不难,只要标记好已知要选的种类,在另一个序列里就会有众多子段,取和最大的子段即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m,typ;
const int N = 5e5+10;
int a[N],b[N],x[N],y[N],px[N],py[N],L[N],R[N],stl[N],str[N],topl,topr;
pii col[N],mx[N<<2];
int tag[N<<2];
#define ls p<<1
#define rs p<<1|1
void pushup(int p){
mx[p]=max(mx[ls],mx[rs]);
}
void pushdown(int p){
if(tag[p]){
tag[ls]+=tag[p];tag[rs]+=tag[p];
mx[ls].fst+=tag[p];mx[rs].fst+=tag[p];
tag[p]=0;
}
}
void build(int p,int l,int r){
tag[p]=0;
if(l==r){
mx[p]={px[n]-py[l-1],l};
return;
}
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int ql,int qr,int x){
if(ql>qr)return;
if(ql<=l&&r<=qr){
tag[p]+=x;
mx[p].fst+=x;
return;
}
int mid=(l+r)/2;
pushdown(p);
if(ql<=mid)modify(ls,l,mid,ql,qr,x);
if(qr>mid)modify(rs,mid+1,r,ql,qr,x);
pushup(p);
}
int ans=0,al,ar,bl,br;
void solve(bool flag){
int md=0;
for(int i=1;i<=n;i++){
if(2*px[i]>=px[n]){
md=i;
break;
}
}
for(int i=1;i<=n;i++){
col[i]={a[i],i};
}
sort(col+1,col+1+n);
for(int i=1;i<=m;i++){
int l=1,r=n,res=0;
while(l<=r){
int mid=(l+r)/2;
if(col[mid].fst<=b[i]){
l=mid+1;
res=mid;
}else{
r=mid-1;
}
}
if(!res||b[i]!=col[res].fst)continue;
if(col[res].scd<=md)L[i]=col[res].scd;
else R[i]=col[res].scd;
}
build(1,1,m);
topl=topr=0;
stl[0]=str[0]=0;
for(int r=1;r<=m;r++){
if(L[r]){
while(topl&&L[stl[topl]]<L[r]){
modify(1,1,m,stl[topl-1]+1,stl[topl],px[L[stl[topl]]]);
topl--;
}
stl[++topl]=r;
modify(1,1,m,stl[topl-1]+1,r,-px[L[r]]);
}
if(R[r]){
while(topr&&R[str[topr]]>R[r]){
modify(1,1,m,str[topr-1]+1,str[topr],px[n]-px[R[str[topr]]-1]);
topr--;
}
str[++topr]=r;
modify(1,1,m,str[topr-1]+1,r,-px[n]+px[R[r]-1]);
}
if(mx[1].fst+py[r]>ans){
ans=mx[1].fst+py[r];
if(!flag)bl=mx[1].scd,br=r,typ=0;
else al=mx[1].scd,ar=r,typ=1;
}
}
}
map<int,bool>mp;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
cin>>x[i];
px[i]=px[i-1]+x[i];
}
for(int i=1;i<=m;i++)cin>>b[i];
for(int i=1;i<=m;i++){
cin>>y[i];
py[i]=py[i-1]+y[i];
}
ans=px[n];al=1,ar=n;typ=1;
if(py[m]>ans){ans=py[m];al=0;ar=0;bl=1;br=m;typ=0;}
solve(0);
for(int i=1;i<=max(n,m);i++){
swap(a[i],b[i]);
swap(x[i],y[i]);
swap(px[i],py[i]);
}
swap(n,m);
memset(L,0,sizeof(L));memset(R,0,sizeof(R));
memset(stl,0,sizeof(stl));
memset(str,0,sizeof(str));
for(int i=1;i<N;i++){
col[i]=mkp(0,0);
}
solve(1);
for(int i=1;i<=max(n,m);i++){
swap(a[i],b[i]);
swap(x[i],y[i]);
swap(px[i],py[i]);
}
swap(n,m);
if(!typ){
int l=0,r=0;
for(int i=bl;i<=br;i++){
mp[b[i]]=1;
}
int v=0,lst=0;
for(int i=1;i<=n;i++){
if(mp[a[i]]==1){
if(px[i-1]-px[lst]>v){
v=px[i-1]-px[lst];
l=lst+1,r=i-1;
}
lst=i;
}
}
if(px[n]-px[lst]>v){
v=px[n]-px[lst];
l=lst+1,r=n;
}
if(!v){
l=0,r=0;
}
cout<<ans<<endl;
cout<<l<<" "<<r<<endl;
cout<<bl<<" "<<br<<endl;
}else{
int l=0,r=0;
for(int i=al;i<=ar;i++){
mp[a[i]]=1;
}
int v=0,lst=0;
for(int i=1;i<=m;i++){
if(mp[b[i]]==1){
if(py[i-1]-py[lst]>v){
v=py[i-1]-py[lst];
l=lst+1,r=i-1;
}
lst=i;
}
}
if(py[m]-py[lst]>v){
v=py[m]-py[lst];
l=lst+1,r=m;
}
if(!v){
l=0,r=0;
}
cout<<ans<<endl;
cout<<al<<" "<<ar<<endl;
cout<<l<<" "<<r<<endl;
}
return 0;
}

浙公网安备 33010602011771号