题目链接

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

线段树做法:用单调栈求出每个数两边比它大的左右边界,然后用线段树求出每段区间的和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. DBUS及常用接口介绍

    [原文]  1. 概述 1.1  DBUS概述     DBUS是一种高级的进程间通信机制.DBUS支持进程间一对一和多对多的对等通信,在多对多的通讯时,需要后台进程的角色去分转消息,当一个进程发消息 ...

  2. UOJ34 多项式乘法(NTT)

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  3. 解决httpclient请求响应压缩文本乱码问题

    最近在调用京东的获取省份接口老是中文乱码,加了utf-8也没有用.最后在httpclient打的日志中有Content-Encoding:gzip信息,最后在请求header里加上: reqHeade ...

  4. MySQL Order By Rand()效率分析

    最近研究了一下MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() L ...

  5. [PostgreSql]PostgreSql调用函数及用IF EXISTS判断表是否存在

    1.创建一个函数function1 -- FUNCTION: public.function1(character varying, integer) -- DROP FUNCTION public. ...

  6. mysql数据库开放远程连接的方法

    web与mysql数据库分离开来是一个不错的选择,避免因为大量的数据库查询占用CPU而使web资源不足,同时可以使web服务器的资源尽最大的提供浏览服务,而数据库服务器单独的只处理数据库事物. 适用范 ...

  7. 手动建立Mysql表实体类技巧

    首先执行一条sql语句,也可以在开发中插入数据.修改数据或者查询数据的某个属性时使用. select sc.COLUMN_NAME from information_schema.COLUMNS as ...

  8. C++(二十九) — new 和 delete

    1.基本用法,定义变量.数组.对象 class test { public: test(int a_, int b_) { a = a_; b = b_; cout << "构造 ...

  9. hdu4009最小树形图

    多建一个根,连到每一个点,然后花费是建水井的钱 然后跑一边最小树形图即可,这题必定有解,因为可以从根开始到每一点,可以不用判无解的情况 #include<map> #include< ...

  10. Slasher Flick

    打不死的小强! 返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始. 这是一些对你有帮助的资源: Array.slice() Array.splice() 按照提供的第一种方法,代码如下: f ...