笛卡尔树-P2659 美丽的序列

P2659 美丽的序列

tag 笛卡尔树

题意

找出一个序列的所有子段中子段长度乘段内元素最小值的最大值。

思路

我们需要找出所有子段中贡献最大的,并且一个子段的贡献为其长度乘区间最小值

这……不就是裸的笛卡尔树吗?

建出符合小根堆性质的笛卡尔树,递归所有点,更新答案即可。

因为这是一道裸题,所以我记录一下建笛卡尔树的模板。(从OI wiki上扣的)

思路是用一个单调栈维护一下右链。

伪代码:

新建一个大小为 n 的空栈。用 top 来标操作前的栈顶,k 来标记当前栈顶。
For i := 1 to n
    k := top
    While 栈非空 且 栈顶元素 > 当前元素 
        k--
    if 栈非空
        栈顶元素.右儿子 := 当前元素
    if k < top
        当前元素.左儿子 := 之前栈顶元素
    当前元素入栈
    top := k

C++:

for(int k,i=1;i<=n;i++){
    k=top;
    while(k and a[st[k]]>a[i])k--;
    if(k) rs[st[k]]=i,isrt[i]=1;
    if(k<top) ls[i]=st[k+1],isrt[st[k+1]]=1;
    st[++k]=i;
    top=k;
}

本题实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
	int w=0,x=0;char c=getchar();
	while(!isdigit(c))w|=c=='-',c=getchar();
	while(isdigit(c))x=x*10+(c^48),c=getchar();
	return w?-x:x;
}
namespace star
{
	const int maxn=2e6+10;
	int n,a[maxn],ls[maxn],rs[maxn],st[maxn],top;
	long long ans;
	bool isrt[maxn];
	void dfs(int x,int l,int r){
		ans=max(ans,1ll*a[x]*(r-l+1));
		if(ls[x])dfs(ls[x],l,x-1);
		if(rs[x])dfs(rs[x],x+1,r);
	}
	inline void work(){
		n=read();
		for(int i=1;i<=n;i++) a[i]=read();
		for(int k,i=1;i<=n;i++){
			k=top;
			while(k and a[st[k]]>a[i])k--;
			if(k) rs[st[k]]=i,isrt[i]=1;
			if(k<top) ls[i]=st[k+1],isrt[st[k+1]]=1;
			st[++k]=i;
			top=k;
		}
		int root=0;
		for(int i=1;i<=n;i++) if(!isrt[i]) root=i;
		dfs(root,1,n);
		printf("%lld\n",ans);
	}
}
signed main(){
	star::work();
	return 0;
}

其他

为什么你谷连带log的做法都有就是没人写笛卡尔树呀QAQ

笛卡尔树它多可爱呀~

posted @   Star_Cried  阅读(136)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示