题目链接

题意:求一个序列的最大的(区间最小值*区间和)

线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和sum、最小前缀lsum、最小后缀rsum,枚举每个数a[i],设以a[i]为最小值的区间为[l,r]

若a[i]>0,则最优解就是a[i]*([l,r]的区间和),因为[l,r]上的数都比a[i]大。

若a[i]<0,则最优解是a[i]*([l,i-1]上的最小后缀+a[i]+[i+1,r]上的最小前缀),在线段树上查询即可。

复杂度$O(nlogn)$

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+,inf=0x3f3f3f3f;
int a[N],n,sta[N],L[N],R[N],tp;
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
struct D {ll sum,lsum,rsum;} s[N<<];
D mg(D a,D b) {
D t= {,};
t.sum=a.sum+b.sum;
t.lsum=min(a.lsum,a.sum+b.lsum);
t.rsum=min(b.rsum,b.sum+a.rsum);
return t;
}
void build(int u=,int l=,int r=n) {
if(l==r) {s[u].sum=a[l],s[u].lsum=min((ll)a[l],0ll),s[u].rsum=min((ll)a[l],0ll); return;}
build(ls,l,mid),build(rs,mid+,r),s[u]=mg(s[ls],s[rs]);
}
void qry(int L,int R,D& x,int u=,int l=,int r=n) {
if(l>=L&&r<=R) {x=mg(x,s[u]); return;}
if(l>R||r<L)return;
qry(L,R,x,ls,l,mid),qry(L,R,x,rs,mid+,r);
}
int main() {
scanf("%d",&n);
a[]=a[n+]=~inf;
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
sta[tp=]=;
for(int i=; i<=n; ++i) {
for(; a[sta[tp]]>=a[i]; --tp);
L[i]=sta[tp]+,sta[++tp]=i;
}
sta[tp=]=n+;
for(int i=n; i>=; --i) {
for(; a[sta[tp]]>=a[i]; --tp);
R[i]=sta[tp]-,sta[++tp]=i;
}
build();
ll ans=;
for(int i=; i<=n; ++i) {
if(a[i]>) {
D t= {,};
qry(L[i],R[i],t);
ans=max(ans,a[i]*t.sum);
} else if(a[i]<) {
ll x=;
D t= {,};
qry(L[i],i,t);
x+=t.rsum;
t= {,};
qry(i,R[i],t);
x+=t.lsum;
x-=a[i];
ans=max(ans,a[i]*x);
}
}
printf("%lld\n",ans);
return ;
}

笛卡尔树做法:对整个序列建立笛卡尔树,用和线段树相同的方法求出每个结点的子树所代表区间的sum,lsum,rsum,枚举每个结点,如果是正数则乘上该结点的sum,如果是负数则乘上该结点的(左儿子的rsum+右儿子的lsum+结点本身的值)即可。

复杂度$O(n)$

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+,inf=0x3f3f3f3f;
int n,a[N],ls[N],rs[N],sta[N],tp;
ll sum[N],lsum[N],rsum[N];
void build() {
a[n+]=~inf,sta[tp=]=n+;
for(int i=; i<=n; ++i) {
for(; a[i]<a[sta[tp]]; --tp);
ls[i]=rs[sta[tp]],rs[sta[tp]]=i,sta[++tp]=i;
}
}
void dfs(int u) {
if(!u)return;
dfs(ls[u]),dfs(rs[u]);
sum[u]=sum[ls[u]]+a[u]+sum[rs[u]];
lsum[u]=min(lsum[ls[u]],sum[ls[u]]+a[u]+lsum[rs[u]]);
rsum[u]=min(rsum[rs[u]],sum[rs[u]]+a[u]+rsum[ls[u]]);
}
int main() {
scanf("%d",&n);
for(int i=; i<=n; ++i)scanf("%d",&a[i]);
build(),dfs(rs[n+]);
ll ans=;
for(int i=; i<=n; ++i) {
if(a[i]>)ans=max(ans,a[i]*sum[i]);
else if(a[i]<)ans=max(ans,a[i]*(rsum[ls[i]]+a[i]+lsum[rs[i]]));
}
printf("%lld\n",ans);
return ;
}

2019ICPC南昌邀请赛网络赛 I. Max answer (单调栈+线段树/笛卡尔树)的更多相关文章

  1. 计蒜客 38228. Max answer-线段树维护单调栈(The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer 南昌邀请赛网络赛) 2019ICPC南昌邀请赛网络赛

    Max answer Alice has a magic array. She suggests that the value of a interval is equal to the sum of ...

  2. 南昌邀请赛I.Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value of a in ...

  3. 网络赛 I题 Max answer 单调栈+线段树

    题目链接:https://nanti.jisuanke.com/t/38228 题意:在给出的序列里面找一个区间,使区间最小值乘以区间和得到的值最大,输出这个最大值. 思路:我们枚举每一个数字,假设是 ...

  4. The Preliminary Contest for ICPC China Nanchang National Invitational I. Max answer (单调栈+线段树)

    题目链接:https://nanti.jisuanke.com/t/38228 题目大意:一个区间的值等于该区间的和乘以区间的最小值.给出一个含有n个数的序列(序列的值有正有负),找到该序列的区间最大 ...

  5. 2019南昌邀请赛网络预选赛 I. Max answer(单调栈+暴力??)

    传送门 题意: 给你你一序列 a,共 n 个元素,求最大的F(l,r): F(l,r) = (a[l]+a[l+1]+.....+a[r])*min(l,r); ([l,r]的区间和*区间最小值,F( ...

  6. 南昌邀请赛网络赛 D.Match Stick Game(dp)

    南昌邀请赛网络赛 D.Match Stick Game 题目传送门 题目就会给你一个长度为n的字符串,其中\(1<n<100\).这个字符串是一个表达式,只有加减运算符,然后输入的每一个字 ...

  7. icpc 南昌邀请赛网络赛 Max answer

    就是求区间和与区间最小值的积的最大值 但是a[i]可能是负的 这就很坑 赛后看了好多dalao的博客 终于a了 这个问题我感觉可以分为两个步骤 第一步是对于每个元素 以它为最小值的最大区间是什么 第二 ...

  8. 南昌网络赛 I. Max answer 单调栈

    Max answer 题目链接 https://nanti.jisuanke.com/t/38228 Describe Alice has a magic array. She suggests th ...

  9. 南昌网络赛 I. Max answer (单调栈 + 线段树)

    https://nanti.jisuanke.com/t/38228 题意给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,求所有子区间的最大价值是多少. 分析:我们先用单调栈 ...

随机推荐

  1. java堆排序(大根堆)

    实现堆排序的算法思路是先创建堆,也就是从叶子节点起对每一层的孩子节点及其对应位置的父亲节点进行比较,较大的孩子节点替换较小的父亲节点,一级一级比较替换,就创建出了大根堆,小根堆反之.创建好大根堆以后, ...

  2. P4Lang Repository: Switch

    Github Switch Introduction Structure: +-----+ +-----+ +-----+ +-----+ |App a| |App j| |App n| |App z ...

  3. Python学习札记(十六) 高级特性2 迭代

    参考:迭代 Note 1.如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration). 在C.C++.Java等语言中,for循 ...

  4. 我的nlp之路(1)

    1/8日任务 基础篇: 如何使用远程连接从windows或者linux连到服务器进行操作(切换用户,传递文件) (严禁使用root账户) Linux基本bash命令 a)        查看文件大小, ...

  5. Nginx与PHP(FastCGI)的安装、配置

    摘自:http://www.linuxde.net/2012/03/9130.html 一.什么是 FastCGI FastCGI是一个可伸缩地.高速地在HTTP server和动态脚本语言间通信的接 ...

  6. MySQL事务的隔离级别

    为什么需要隔离 当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,我们先看看如果不考虑事务的隔离性,会发生的几种 ...

  7. 17.并发容器之ThreadLocal

    1. ThreadLocal的简介 在多线程编程中通常解决线程安全的问题我们会利用synchronzed或者lock控制线程对临界区资源的同步顺序从而解决线程安全的问题,但是这种加锁的方式会让未获取到 ...

  8. IOS-涂鸦

    // // PaintView.m // IOS_0224_涂鸦 // // Created by ma c on 16/2/24. // Copyright © 2016年 博文科技. All ri ...

  9. 【zznu-夏季队内积分赛3-F】学无止境

    题目描述 “别人总说我瓜,其实我一点也不瓜,大多数时候我都机智的一批“ACM程序设计竞赛是一个团体项目.宝儿姐作为其中优秀的一份子,每天好好学习天天向上.曾经宝儿姐给自己定了一个计划,刷穿bzoj.于 ...

  10. C# 设计模式巩固 - 抽象工厂模式

    前言   继续工厂模式高级版,抽象工厂模式.抽象工厂模式其实是从工厂方法模式拓展而来.在实际的生活中一个工厂的产品不可能是单一的,肯定是多种系列的产品. 介绍 - 抽象工厂模式 定义:(摘自百度百科~ ...