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;
}

posted @ 2025-06-05 16:21  Add_Catalyst  阅读(11)  评论(0)    收藏  举报