计蒜客38228 Max answer 单调栈 + 线段树

Max answer
POJ 2796 Feel Good类似,但是这个题有负数,需要特殊处理一下

#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

#define iall 1, n, 1
#define lrrt int l, int r, int rt
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1

const int MAXN = 500000 + 16;
const LL INF = 0x7F7F7F7F7F7F7F7F;
LL a[MAXN], sum[MAXN];
LL max_tree[MAXN << 2], min_tree[MAXN << 2];
int STK[MAXN], top;
int L[MAXN], R[MAXN];
int n;

void build(lrrt) {
    max_tree[rt] = min_tree[rt] = 0;
    if (l == r) {
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
}

void add(lrrt, int x, int v) {
    if (l == r) {
        max_tree[rt] = min_tree[rt] = v;
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid) add(lson, x, v);
    else add(rson, x, v);
    max_tree[rt] = max(max_tree[rt << 1], max_tree[rt << 1 | 1]);
    min_tree[rt] = min(min_tree[rt << 1], min_tree[rt << 1 | 1]);
}

LL query_min(lrrt, int x, int y) {
    if (x <= l && r <= y) {
        return min_tree[rt];
    }
    int mid = (l + r) >> 1;
    if (x > mid) return query_min(rson, x, y);
    else if (y <= mid) return query_min(lson, x, y);
    else return min(query_min(lson, x, y), query_min(rson, x, y));
}

LL query_max(lrrt, int x, int y) {
    if (x <= l && r <= y) {
        return max_tree[rt];
    }
    int mid = (l + r) >> 1;
    if (x > mid) return query_max(rson, x, y);
    else if (y <= mid) return query_max(lson, x, y);
    else return max(query_max(lson, x, y), query_max(rson, x, y));
}

LL get_max(int x, int y) {
    if (y == 0)
        return 0;
    if (x == 0) {
        return max(LL(0), query_max(iall, 1, y));
    }
    return query_max(iall, x, y);
}

void get_lr() {
    top = 0;
    for (int i = 1; i <= n; ++i) {
        L[i] = i;
        while (top && a[i] < a[STK[top]]) {
            L[i] = L[STK[top]];
            R[STK[top]] = i - 1;
            --top;
        }
        STK[++top] = i;
    }
    while (top) {
        R[STK[top--]] = n;
    }
}

int main(int argc, char **argv) {
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]); a[n + 1] = -INF;
        for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
        get_lr();
        build(iall);
        for (int i = 1; i <= n; ++i) add(iall, i, sum[i]);
        LL ans = -INF;
        for (int i = 1; i <= n; ++i) {
            if (a[i] >= 0) {
                LL tmp = a[i] * (sum[R[i]] - sum[L[i] - 1]);
                ans = max(ans, tmp);
            } else {
                LL sr = query_min(iall, i, R[i]);
                LL sl = get_max(L[i] - 1, i - 1);
                LL tmp = a[i] * (sr - sl);
                ans = max(ans, tmp);
            }
        }
        printf("%lld\n", ans);
    }
}

/**
5
1 2 3 4 5
5
-1 -2 -3 -4 -5
7
1 2 3 -1 -2 -3 8
7
1 2 3 -1 -2 -3 1
9
1 2 3 -1 -2 -3 8 -100 100

*/

原文地址:https://www.cnblogs.com/ToRapture/p/10763537.html

时间: 2024-10-01 20:07:48

计蒜客38228 Max answer 单调栈 + 线段树的相关文章

The Preliminary Contest for ICPC China Nanchang National Invitational I.Max answer单调栈

题面 题意:一个5e5的数组,定义一个区间的值为 这个区间的和*这个区间的最小值,注意数组值有负数有正数,求所有区间中最大的值 题解:如果全是正数,那就是原题 POJ2796 单调栈做一下就ok 我们现在有负数,考虑这段区间,他的和必须是负数,由于导致和为负数,最小值一定也是负数, 那对于这样一个和为负的区间进行扩展的时候,遇见下一个数,是负数,我们一定会扩展,无论这个负数大小 遇见下一个是正数,如果和没有变正,那就可以继续扩展下去(不更新答案罢了) 所以我们对于那些和为负的区间,单独统计一下答

单调栈+线段树

262144K Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval. Now she is planning to find the max value of the intervals in her array. C

【CF671E】Organizing a Race 单调栈+线段树

[CF671E]Organizing a Race 题意:n个城市排成一排,每个城市内都有一个加油站,赛车每次经过第i个城市时都会获得$g_i$升油.相邻两个城市之间由道路连接,第i个城市和第i+1个城市之间的道路长度为$w_i$,走一单位的路要花1升油.你想在某两个城市之间举办一场锦标赛.如果你选择的两个城市分别是a和b(a<b),则具体过程如下: 1. 赛车从a开始往右走一直走到b,走过城市时会在加油站加油,走过道路时会消耗油,且一开始时就已经在a处加完油了.你需要满足赛车能有足够的油能从a

2019南昌网络赛-I(单调栈+线段树)

题目链接:https://nanti.jisuanke.com/t/38228 题意:定义一段区间的值为该区间的和×该区间的最小值,求给定数组的最大的区间值. 思路:比赛时还不会线段树,和队友在这题上弄了3小时,思路大体都是对的,但就是没法实现.这几天恶补线段树. 首先可以利用单调栈来查找满足a[i]为最小值的最大区间L[i]~R[i].然后利用线段树求一个段的和sum.最小前缀lsum和最小后缀rsum.然后遍历a[i]: a[i]>0:最优为sum(L[i],R[i])*a[i] a[i]<

计蒜客模拟赛D1T2 蒜头君的树:树上节点之间最短距离和

题目链接:https://nanti.jisuanke.com/t/16446 题意: 给你一棵有n个节点的树以及每条边的长度,输出树上节点之间的最短距离和.然后进行m次操作,每次操作更改一条边的长度,分别输出每次操作后树上节点之间的最短距离和. 题解: 最短距离和 = ∑(树上每一条边被最短路经过的次数 * 这条边的长度) 一个节点到它父节点的边被经过的次数 = 该节点以及它的子孙的节点个数 * 除了该节点和它子孙之外的所有节点总个数 每一个节点以及它子孙节点的个数总和用一遍dfs保存在num

计蒜客 无脑博士和他的试管们

无脑博士有三个容量分别是A,B,C升的试管,A,B,C分别是三个从1到20的整数,最初,A和B试管都是空的,而C试管是装满硫酸铜溶液的.有时,无脑博士把硫酸铜溶液从一个试管倒到另一个试管中,直到被灌试管装满或原试管空了.当然每一次灌注都是完全的.由于无脑博士天天这么折腾,早已熟练,溶液在倒的过程中不会有丢失. 写一个程序去帮助无脑博士找出当A是个是空的时候,C试管中硫酸铜溶液所剩量的所有可能性. 输入包括一行,为空格分隔开的三个数,分别为整数A,B和C. 输出包括一行,升序地列出当A试管是空的时

计蒜客普及组模拟赛

今天没事闲的看到计蒜客有个普及组模拟赛,就当练了练手去打了,成绩低的可怜...400分崩成280分AK梦想化作泡影 第一题 同学的爱好 链接:https://nanti.jisuanke.com/t/17291 小学应用题难度?大概画个图就能懂,把每个部分都标上号,算出a,b,c,d,e,f的部分,进行运算就行了. 不多解释了,直接上代码 #include<iostream> #include<cstdio> #include<algorithm> #include&l

简单斐波那契——计蒜客(4)

题目来自“计蒜客”第4题. 解算法题之前,务必先写出与之对应的数学表达式,用于描述算法. 数学描述如图: 根据“数学描述“,写出代码如下: #include <stdio.h> int main() { int N =0 ; scanf("%d", &N); int i, fn1 = 1, fn2 = 0, fn; switch(N) { case 0: printf("0"); break; case 1: printf("1&quo

计蒜客 作弊揭发者(string的应用)

鉴于我市拥堵的交通状况,市政交管部门经过听证决定在道路两侧安置自动停车收费系统.当车辆驶入车位,系统会通过配有的摄像头拍摄车辆画面,通过识别车牌上的数字.字母序列识别车牌,通过连接车管所车辆信息数据库确认车辆,进行扣费. 斗智斗勇的好戏一般从此处展开… 一些车主通过在停车时遮挡车牌上的一个或多个数字.字母序列,来阻碍识别系统的识别工作,以此逃避停车费用的缴纳. 车主这简直是用轻轻的一挡搞出来一个世界难题有木有?!管理是一方面,技术解决才是王道啊. 这么难的项目不得不交给计蒜客实验室了.D 神负责