← 回到所有文章

P14311 【MX-S8-T4】平衡三元组 题解

出题人题解,欢迎观看视频题解,打不开的把链接 首先转化条件为 2Byleq Bx+Bz。 那么就是在区间 l,r 内找三个下标 lleq x<y<zleq r,2Ayleq Ax+Az,最大化 Ax+…

题解文章的简约插画封面

出题人题解,欢迎观看视频题解,打不开的把链接https://www.bilibili.com/video/BV1hhsfzYEdc/复制下来打开。

首先转化条件为 2By≤Bx+Bz2B_y\leq B_x+B_z。

那么就是在区间 l,rl,r 内找三个下标 l≤x<y<z≤r,2Ay≤Ax+Azl\leq x<y<z\leq r,2A_y\leq A_x+A_z,最大化 Ax+Ay+AzA_x+A_y+A_z。

提示1:考虑固定 yy 的时候,x,zx,z 的取值。

这个时候 xx 肯定取到 [l,y)[l,y) 的最大值,同理 zz 取到 (y,r](y,r] 的最大值。

于是可以快速得到一个 O(nq)\mathcal{O}(nq) 的做法,对于区间做前缀和后缀最大值,枚举 yy 的位置即可。

继续优化,观察 x,y,zx,y,z 还有什么性质。

观察到:由于 x,zx,z 覆盖了整个左右区间,那么 x,zx,z 中一定有一个是区间最大值。

根据这点,我们钦定 aa 是区间最大值,作为 xx,接下来考虑 yy 放在什么地方,zz 是 (y,r](y,r] 的最大值。

于是自然的想到一个特殊的 zz,为 (a,r](a,r] 的最大值,记为 a0a_0。那么 ∀y∈(a,a0)\forall y\in(a,a_0) 都有 y≤Aa0≤Aay\leq A_{a_0}\leq A_{a},于是 (a,y,a0)(a,y,a_0) 合法,可以贡献答案。

分析一下,到这个时候我们已经考虑了 y∈(a,a0)y\in (a,a_0) 的所有情况,接下来考虑 y=a0y=a_0 的情况,记 a1a_1 为 (a0,r](a_0,r] 的最大值,如果 (a,a0,a1)(a,a_0,a_1) 合法则可以贡献答案。

这个时候已经考虑 y∈(a,a0]y\in (a,a_0] 的所有情况。如果 (a,a0,a1)(a,a_0,a_1) 合法,对于 ∀y∈(a0,r],Ay≤Aa0\forall y\in(a_0,r],A_y\leq A_{a_0} 以及 ∀z∈(a0,r],Az≤Aa1\forall z\in(a_0,r],A_z\leq A_{a_1},可以得到不会有更好的 (a,x,y)(a,x,y) 了。

如果 (a,a0,a1)(a,a_0,a_1) 不合法怎么办?只有继续考虑 y∈(a0,r]y\in(a_0,r] 的情况。

延续刚才的想法,我们先钦定 z=a1z=a_1,那么 ∀y∈(a0,a1)\forall y\in(a_0,a_1) 都有 (a,y,a1)(a,y,a_1) 合法,并且可以找到 a2a_2 是 (a1,r](a_1,r] 的最大值,尝试贡献 (a,a1,a2)(a,a_1,a_2)。

可以立刻意识到我们进入了一个和刚才相似的递归子结构,到这里我们处理了 y∈(a,a1]y\in (a,a_1] 的所有情况。

提示2:尝试分析是否会继续递归吗?最多递归多少层?

直接分析 2Aa0>Aa+Aa12A_{a_0}> A_a+A_{a_1} 那么 Aa1<2Aa0−AaA_{a_1}<2A_{a_0}-A_a。

接下来 2Aa1>Aa+Aa22A_{a_1}>A_a+A_{a_2},那么 Aa2<2Aa1−Aa<4Aa0−3AaA_{a_2}<2A_{a_1}-A_a<4A_{a_0}-3A_a。

归纳一下 Ai<2iAa0−(2i−1)Aa=Aa−2i(Aa−Aa0)A_i< 2^iA_{a_0}-(2^i-1)A_a=A_a-2^i(A_a-A_{a_0})。

所以如果 Aa≠Aa0A_a\not=A_{a_0},只会递归 O(log⁡V)\mathcal{O}(\log V) 次。如果 Aa=Aa0A_a=A_{a_0} 则从 a1a_1 开始归纳也一样,如果 Aa=Aa0=Aa1A_a=A_{a_0}=A_{a_1} 那么 (a,a0,a1)(a,a_0,a_1) 就已经合法了。

总结一下只需要求区间最大值和其位置,修改只有区间加法,线段树即可解决。时间复杂度 O(qlog⁡Vlog⁡n)\mathcal{O}(q\log V\log n),这里认为 qXqX 和 VV 同阶。

#include<bits/stdc++.h>

#define NOBUG
// #define ONLINE_JUDGE
#define il inline __attribute((always_inline)) 

#ifdef NOBUG
#define dbg(...) fprintf (stderr, __VA_ARGS__)
#else
#define dbg(...) void()
#endif

using u32=unsigned int;
using i64=long long;
using u64=unsigned long long;

const i64 INF=0x3f3f3f3f3f3f3f3fll;

#define lc (p<<1)
#define rc (lc|1)

i64 tag[1000010<<2];

struct NODE{
	i64 max;
	int pos;
	NODE operator + (const NODE &o) const{
		i64 mx=std::max(max,o.max);
		int p=0;
		if(max==mx) p=pos;
		if(o.max==mx) p=o.pos;
		return {mx,p};
	}
}tree[1000010<<2];

void down(int p,i64 x){
	tree[p].max+=x;
	tag[p]+=x;
}

void pushdown(int p){
	down(lc,tag[p]),down(rc,tag[p]);
	tag[p]=0;
}
void pushup(int p){
	tree[p]=tree[lc]+tree[rc];
}

void read(int p,int l,int r){
	if(l==r){
		tree[p]={0,l};
		scanf("%lld",&tree[p].max);
		return;
	}
	int mid=(l+r)>>1;
	read(lc,l,mid),read(rc,mid+1,r);
	pushup(p);
}

void modify(int p,int l,int r,int s,int t,int x){
	if(s<=l&&r<=t) return down(p,x);
	int mid=(l+r)>>1;
	pushdown(p);
	if(s<=mid) modify(lc,l,mid,s,t,x);
	if(mid<t) modify(rc,mid+1,r,s,t,x);
	pushup(p);
}

NODE qry(int p,int l,int r,int s,int t){
	if(s<=l&&r<=t) return tree[p];
	int mid=(l+r)>>1;
    pushdown(p);
	NODE res={-INF,0};
	if(s<=mid) res=res+qry(lc,l,mid,s,t);
	if(mid<t) res=res+qry(rc,mid+1,r,s,t);
	return res;
}

int n;

NODE qry(int l,int r,char rev){
	if(rev){
		l=n-l+1,r=n-r+1;
		std::swap(l,r);
	}
	if(l>r) return {-INF,0};
    NODE res=qry(1,1,n,l,r);
    if(rev) res.pos=n-res.pos+1;
	return res;
}

int cnt=0;

i64 calc(int l,int r,char rev){
	NODE n1=qry(l,r,rev),n2,n3;
	i64 res=-INF;
	n2=n1,n3=qry(n1.pos+1,r,rev);
	while(n3.pos){
		++cnt;
		res=std::max(res,n1.max+qry(n2.pos+1,n3.pos-1,rev).max+n3.max);
		n2=n3;
		n3=qry(n2.pos+1,r,rev);
		if(n2.max*2<=n1.max+n3.max){
			res=std::max(res,n1.max+n2.max+n3.max);
			break;
		}
	}
    return res;
}

int main(){
	#ifndef ONLINE_JUDGE
	freopen("d_6_4.in", "r", stdin);
	freopen("name.out", "w", stdout);
	#endif

	int o,l,r,x,q;
	scanf("%d%d",&n,&q);
	read(1,1,n);
	while(q--){
		scanf("%d%d%d",&o,&l,&r);
		if(o==1){
			i64 res=std::max(calc(l,r,0),calc(n-r+1,n-l+1,1));
            if(res<=-INF/2) puts("No");
            else printf("%lld\n",res);
		}else{
			scanf("%d",&x);
			modify(1,1,n,l,r,x);
		}
	}

    return 0;
}

谢谢你,读到这里。

本文同步自洛谷专栏,保留原始正文与发布时间。在洛谷查看原文 ↗

搜索文章

输入关键词,发现一些值得阅读的文字。

探索文字里的小小世界esc 关闭