首页 > 其他分享 >「JOI Open 2019」三级跳 题解

「JOI Open 2019」三级跳 题解

时间:2024-02-14 22:11:07浏览次数:29  
标签:return lc int 题解 mid 端点 JOI Open lz

https://loj.ac/p/3153

Part1 暴力

暴力思路:每次询问的时候,枚举 \(a\) 和 \(b\) 在哪里,然后就确定了 \(c\) 的范围 \([2\times b-a]\),找这个范围内的最大的 A[c] 即可。

Part2优化

舍解

考虑哪一些 \([a,b]\) 是明显不优的。如果存在 \(i\),满足 \(a<i<b\) 且 \(A[i]<\min(A[a],A[b])\) 那么一定可以缩小 \(a,b\) 中的一个到 \(i\),缩小之后 \(A[a]+A[b]\) 的值更大,并且 \(b-a\) 更小(给了 \(c\) 更大的范围),所以显然原先的 \([a,b]\) 是不够优秀的。

怎么计算优秀的对?

观察发现,一个点 \(i\) 作为左端点时,第一个 \(j\) 满足 \(j>i,a[j]\ge a[i]\),能够作为右端点。一个点 \(i\) 作为右端点时,最后一个 \(j\) 满足 \(j<i,a[j]\ge a[j]\),能够作为左端点。其它的,\(i\) 在端点处的都是不优的。所以,对每一个 \(i\),找两侧距离它最近的大于 \(A[i]\) 的值作为端点。可以用单调栈,也可以用链表。

现在优秀的的数量就是 \(O(n)\) 的。

一次询问的操作

令 \(c[i]\) 表示一个位置 \(i\) 作为 \(c\) 的最大的 \(A[a]+A[b]\).

一次询问就是要在 \([L,R]\) 范围内找最大的 \(c[i]+a[i]\)。

\(a[i]\) 已知,\(c[i]\) 怎么求?

考虑一对 \([a,b]\) 对 \(c\) 数组 的影响。

对于所有 \(i\ge 2\times b-a\) 的,\(c[i]=max(c[i],A[a]+A[b])\)

这不就是区间修改吗?

所以,我们把所有 \(a\ge L\) 的 \([a,b]\) 拿来更新 \(c\) 数组,再询问 \(c\) 数组的某一部分的最大值。单次复杂度为 \(O(n)\)

多次询问

瓶颈是:找所有 \(a\ge L\) 的 \([a,b]\),怎么优化?离线。

把询问按左端点从大到小排序,枚举 \(L\),加入 \(L\) 作为左端点的对,更新他们对 \(c\) 的改变。然后更新左端点为 \(L\) 的询问的答案。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=5e5+5;
int rd(){
	int x=0;bool f=0;char c=getchar();
	while(c>'9'||c<'0'){f|=(c=='-');c=getchar();}
	while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f?-x:x;
}
ll a[MAXN];
#define pii pair<int,int>
#define fi first
#define se second
vector<pii> que[MAXN];
int n;
#define lc (u<<1)
#define rc (u<<1|1)
ll C[MAXN<<2],A[MAXN<<2];//c:当前位置作为c,可选的最大的一对数的值 C=max(c)
ll mx[MAXN<<2];//A+C的最大值
ll lz[MAXN<<2];//取max的懒惰标记
inline void upd(int u){
	A[u]=max(A[lc],A[rc]);
	C[u]=max(C[lc],C[rc]);
	mx[u]=max(mx[lc],mx[rc]);
}
void build(int u,int l,int r){
	if(l==r){
		A[u]=a[l];C[u]=0;mx[u]=A[u];
		return;
	}
	int mid=l+r>>1;
	build(lc,l,mid),build(rc,mid+1,r);
	upd(u);
}
inline void to(int u,ll v){//用v更新u
	C[u]=max(C[u],v);
	mx[u]=max(mx[u],A[u]+v);
	lz[u]=max(lz[u],v);
}
inline void down(int u){
	if(!lz[u])	return;
	to(lc,lz[u]),to(rc,lz[u]);
	lz[u]=0;
}
void work(int u,int l,int r,int L,int R,int v){
	if(r<L||l>R)	return;
	if(r<=R&&l>=L){
		to(u,v);
		return;
	}
	int mid=l+r>>1;down(u);
	work(lc,l,mid,L,R,v),work(rc,mid+1,r,L,R,v);
	upd(u);
}
ll getmax(int u,int l,int r,int L,int R){
	if(r<L||l>R)	return 0;
	if(r<=R&&l>=L)	return mx[u];
	int mid=l+r>>1;down(u);
	return max(getmax(lc,l,mid,L,R),getmax(rc,mid+1,r,L,R));
}
vector<int> b[MAXN];//a=i时,b[i]中的数可以作为b
int sta[MAXN],tp;
void Pre(){//计算有那些对
	for(int i=1;i<=n;i++){
		while(tp&&a[sta[tp]]<=a[i]){
			b[sta[tp]].push_back(i);//(sta[tp],i)
			tp--;
		}
		sta[++tp]=i;
	}
	tp=0;
	for(int i=n;i>=1;i--){
		while(tp&&a[sta[tp]]<=a[i]){
			b[i].push_back(sta[tp]);
			tp--;
		}
		sta[++tp]=i;
	}
	for(int i=1;i<=n;i++){
		sort(b[i].begin(),b[i].end());
		int cnt=unique(b[i].begin(),b[i].end())-b[i].begin();
		// printf("%d\n",cnt);
		b[i].resize(cnt);
		// for(int j:b[i])	printf("%d %d\n",i,j); 
	}
}
int ans[MAXN];
int main(){
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)	a[i]=rd();
	Pre();
	int Q=rd();
	for(int i=1;i<=Q;i++){
		int l=rd(),r=rd();
		que[l].push_back({r,i});
	}
	build(1,1,n);
	for(int i=n;i>=1;i--){
		for(int j:b[i])	if(2*j-i<=n)work(1,1,n,2*j-i,n,a[i]+a[j]);
		for(pii t:que[i]){
			int r=t.fi;
			ans[t.se]=getmax(1,1,n,i,r);
		}
	}
	for(int i=1;i<=Q;i++)	printf("%d\n",ans[i]);
	return 0;
}

标签:return,lc,int,题解,mid,端点,JOI,Open,lz
From: https://www.cnblogs.com/bwartist/p/18015686/loj3153

相关文章

  • OpenLens 6.3.0 无法查案日志和进入 Pod Shell 解决方法
    原因OpenLens6.3.0开始移除了Pod的查看日志和进入PodShell按钮,无法查看日志和进入Pod操作。解决办法OpenLens6.3.0开始这两个功能以插件形式提供,需下载openlens-node-pod-menu插件才能看到这两个按钮。插件地址https://github.com/alebcay/openlens-node-pod-menu安装插......
  • P4113 [HEOI2012] 采花 题解
    题目链接:采花这题数据加强到卡了\(2e6\)的可持久化线段树在线做法,先给只tle了最后一个点的代码:卡常参照代码#include<bits/stdc++.h>//#pragmaGCCoptimize(2)//#pragmaGCCoptimize("Ofast,no-stack-protector,unroll-loops,fast-math")//#pragmaGCCtarget("......
  • LOJ #2876. 「JOISC 2014 Day2」水壶 题解
    DescriptionJOI君所居住的IOI市以一年四季都十分炎热著称。IOI市被分成\(H\)行,每行包含\(W\)块区域。每个区域都是建筑物、原野、墙壁之一。IOI市有\(P\)个区域是建筑物,坐标分别为\((A_1,B_1),\)\((A_2,B_2),\)\(\ldots,\)\((A_P,B_P)\)。JOI君只能进入建......
  • CF1931F Chat Screenshots 另一种题解
    题目链接:CF或者洛谷本题拓扑排序不再赘述,来说说字符串哈希怎么做这题。本篇以另一种角度剖析题目背景,并不追求最优,例如有些地方其实可以暴力判断,主要以构造的角度阐述,顺便感谢灵茶山的朋友的讨论。结论三个串及其以上必定能构造出最初的那个串。下面进行证明:首先一个串,显......
  • 「JOI Open 2019」三段跳び
    题意:\(n\)个数,\(q\)次查询,每次给出区间\([l,r]\),求区间内满足以下条件的三元组\((x,y,z)\)中\(a_{x}+a_{y}+a_{z}\)的最大值:\(x<y<z\)。\(y-x\lez-y\)。做法考虑可能成为答案的\(x\)和\(y\)组成的二元组\((x,y)\)是很少的。事实上,这是\(\mathcalO(n)\)......
  • P8683题解
    首先,看题目描述,给定N个加号,与M个减号,要你求后缀表达式最大值,实际上就是求这些符号和数字排列起来的最大值。这题很容易让人想到贪心。但是呢,又怎么个贪心法呢?很容易看出来,我们可以先用sort进行这么一个排序,之后,我们对于前N大的数加起来,对于剩下的数就减去,于是代码大体就......
  • 麦肯锡问题解决流程-为希望提升水平的产品经理量身定制
    您是否想知道世界上最成功的产品经理如何始终如一地提供不仅满足而且超出预期的解决方案?秘密可能就在于世界上最负盛名的咨询公司之一麦肯锡公司所磨练的方法论。本文深入探讨了麦肯锡的问题解决流程,该流程专为希望提升水平的产品经理量身定制。01.麦肯锡方法:产品管理风......
  • openJudge | 统计学生信息(使用动态链表完成)C语言
    总时间限制:1000ms内存限制:65536kB描述利用动态链表记录从标准输入输入的学生信息(学号、姓名、性别、年龄、得分、地址)其中,学号长度不超过20,姓名长度不超过40,性别长度为1,地址长度不超过40输入包括若干行,每一行都是一个学生的信息,如:00630018zhouyanm2010.028......
  • OpenCL规约算法例子
    本文给出一个规约算法求数组的和的例子。本例子求20000000(两千万)个整数的和。运算过程分成了两步,第一步是GPU对每一个工作组内规约求和,然后将每个工作组的求和结果放到数组中输出。第二步是对输出的数组用CPU求和。实际运行对比发现GPU的效率不如用CPU直接求和。下述算法运行环境......
  • SP34020 ADAPET - Ada and Pet 题解
    题目传送门前置知识前缀函数与KMP算法解法经检验样例,我们发现\(|S|k\)并不是最优答案。考虑利用luoguP4391[BOI2009]RadioTransmission无线传输结论的逆命题,首先必须要有一个完整的\(S\),然后将\(|S|-next_{S}\)复制\(k-1\)次即可。故\(|S|+(|S|-next_{|S|}......