P10656 [ROI 2017] 学习轨迹 (Day 2) 题解
P10656 [ROI 2017] 学习轨迹 (Day 2) 题解
知识点
线段树,单调栈。
分析
首先分析最特殊的情况——只选某一个序列的全部值,这导致后面考虑两个序列都选的时候,其中至少一个序列满足:选的区间和大于整个区间的一半。
因为如果两个序列选的区间和都小于等于其总和一半,那么我们完全可以只选总和最大的那个序列。
这个性质有什么用呢?假设现在满足「选的区间和大于整个区间的一半」的是第一个序列 \(\set{a_i}\)(假设两个序列分别为 \(a,b\))。
那么会发现,无论如何合法地移动区间,有一个点总会被选到。于是我们可以把这个点找出来,然后维护包含这个点的最大合法区间。
实现
仍然是假设现在满足「选的区间和大于整个区间的一半」的是 \(\set{a_i}\),设「\(\set{a_i}\) 中总会被选到的点」为 \(pos\)。
我们考虑在 \(b\) 序列上扫过去,维护 \(r\) 固定时,所有 \(b\) 序列上区间选定为 \([i,r](i\le r)\) 时的答案。
开一棵线段树,记 \((l_i,r_i,v_i)\) 为答案,由于 \(l_i\) 随 \(i\) 单调不增,\(r_i\) 随 \(i\) 单调不增,我们只要单调栈就可以解决更新。具体地,我们分别预处理出对于每种值在 \(pos\) 左边的最大位置和在右边的最小位置,就可以单调栈处理,每次从单调栈中删除元素的时候区间更新。
如果满足「选的区间和大于整个区间的一半」的是 \(\set{b_i}\),也同理再处理一遍即可。
代码
#define Plus_Cat "study"
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pii pair<int,int>
#define Swap(a,b) ((a)^=(b)^=(a)^=(b))
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(5e5+10);
namespace IOEcat {
//Fast IO...
} using namespace IOEcat;
int n,m;
int a[N],b[N],c[N<<1],mxl[N<<1],mnr[N<<1];
Pii A,B;
ll ans;
ll x[N],y[N],X[N],Y[N];
struct Tag {
int l,r;
ll add;
Tag(int l=0,int r=0,ll add=0):l(l),r(r),add(add) {}
friend Tag operator +(Tag A,Tag B) { return Tag(B.l?B.l:A.l,B.r?B.r:A.r,A.add+B.add); }
};
struct Data {
int pos,l,r;
ll val;
Data(int pos=0,int l=0,int r=0,ll val=0):pos(pos),l(l),r(r),val(val) {}
friend Data operator +(Data A,Data B) { return A.val>B.val?A:B; }
friend Data operator +(Data A,Tag B) { return Data(A.pos,B.l?B.l:A.l,B.r?B.r:A.r,A.val+B.add); }
};
struct SEG {
struct node {
Data data;
Tag tag;
node(Data data=Data(),Tag tag=Tag()):data(data),tag(tag) {}
void down(Tag _tag) { data=data+_tag,tag=tag+_tag; }
} tr[N<<2];
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
void Up(int p) { tr[p].data=tr[ls].data+tr[rs].data; }
void Down(int p) { tr[ls].down(tr[p].tag),tr[rs].down(tr[p].tag),tr[p].tag=Tag(); }
void Build(int p=1,int l=1,int r=m) {
tr[p].tag=Tag();
if(l==r)return tr[p].data=Data(l,1,n,X[n]-Y[l-1]),void();
Build(ls,l,mid),Build(rs,mid+1,r),Up(p);
}
void Update(int L,int R,int dl,int dr,int p=1,int l=1,int r=m) {
if(L<=l&&r<=R) {
if(dl)tr[p].down(Tag(dl,0,-(X[dl-1]-X[tr[p].data.l-1])));
if(dr)tr[p].down(Tag(0,dr,-(X[tr[p].data.r]-X[dr])));
return;
}
Down(p);
if(L<=mid)Update(L,R,dl,dr,ls,l,mid);
if(mid<R)Update(L,R,dl,dr,rs,mid+1,r);
Up(p);
}
Data Query(int L,int R,int p=1,int l=1,int r=m) {
if(L<=l&&r<=R)return tr[p].data;
Down(p);
if(R<=mid)return Query(L,R,ls,l,mid);
if(mid<L)return Query(L,R,rs,mid+1,r);
return Query(L,R,ls,l,mid)+Query(L,R,rs,mid+1,r);
}
#undef ls
#undef rs
#undef mid
} seg;
void Solve(const bool univ,Pii &A,Pii &B) {
if(univ) {
Swap(n,m);
FOR(i,1,max(n,m))Swap(a[i],b[i]);
FOR(i,1,max(n,m))Swap(x[i],y[i]);
}
/*DE("Calculate");*/
FOR(i,1,n)X[i]=X[i-1]+x[i];
FOR(i,1,m)Y[i]=Y[i-1]+y[i];
seg.Build();
/*DE("Find Position");*/
int pos(0);
FOR(i,1,n)if(X[i]>(X[n]>>1)&&(pos=i,true))break;
FOR(i,1,c[0])mxl[i]=1,mnr[i]=n;
FOR(i,1,pos)mxl[a[i]]=i+1;
DOR(i,n,pos)mnr[a[i]]=i-1;
/*DE("Solve");*/
int tA(0),tB(0);
static int stA[N],stB[N];
FOR(i,1,m) {
while(tA&&mxl[b[stA[tA]]]<mxl[b[i]])seg.Update(stA[tA-1]+1,stA[tA],mxl[b[i]],0),--tA;
while(tB&&mnr[b[stB[tB]]]>mnr[b[i]])seg.Update(stB[tB-1]+1,stB[tB],0,mnr[b[i]]),--tB;
seg.Update(stA[++tA]=i,stB[++tB]=i,mxl[b[i]],mnr[b[i]]);
Data res(seg.Query(1,i));
if(res.val+Y[i]>ans)ans=res.val+Y[i],A= {res.l,res.r},B= {res.pos,i};
}
}
signed main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
I(n,m);
FOR(i,1,n)I(a[i]),c[++c[0]]=a[i];
FOR(i,1,n)I(x[i]);
FOR(i,1,m)I(b[i]),c[++c[0]]=b[i];
FOR(i,1,m)I(y[i]);
sort(c+1,c+c[0]+1),c[0]=unique(c+1,c+c[0]+1)-c-1;
FOR(i,1,n)a[i]=lower_bound(c+1,c+c[0]+1,a[i])-c;
FOR(i,1,m)b[i]=lower_bound(c+1,c+c[0]+1,b[i])-c;
ll sumA(0),sumB(0);
FOR(i,1,n)sumA+=x[i];
FOR(i,1,m)sumB+=y[i];
sumA>=sumB?(ans=sumA,A= {1,n},B= {0,0}):(ans=sumB,A= {0,0},B= {1,m});
Solve(0,A,B),Solve(1,B,A),O(ans,'\n',A.first,' ',A.second,'\n',B.first,' ',B.second,'\n');
return 0;
}

浙公网安备 33010602011771号