Codeforces 1107G 线段树最大子段和 + 单调栈

G. Vasya and Maximum Profit

Description:

Vasya got really tired of these credits (from problem F) and now wants to earn the money himself! He decided to make a contest to gain a profit.

Vasya has \(n\) problems to choose from. They are numbered from \(1\) to \(n\). The difficulty of the \(i\)-th problem is \(d_i\). Moreover, the problems are given in the increasing order by their difficulties. The difficulties of all tasks are pairwise distinct. In order to add the \(i\)-th problem to the contest you need to pay \(c_i\) burles to its author. For each problem in the contest Vasya gets \(a\) burles.

In order to create a contest he needs to choose a consecutive subsegment of tasks.

So the total earnings for the contest are calculated as follows:

if Vasya takes problem \(i\) to the contest, he needs to pay \(c_i\) to its author; for each problem in the contest Vasya gets \(a\) burles; let \(gap(l, r) = \max\limits_{l \le i < r} (d_{i + 1} - d_i)^2\). If Vasya takes all the tasks with indices from \(l\) to \(r\) to the contest, he also needs to pay \(gap(l, r)\). If \(l = r\) then \(gap(l, r) = 0\). Calculate the maximum profit that Vasya can earn by taking a consecutive segment of tasks.

Input:

The first line contains two integers \(n\) and \(a\) (\(1 \le n \le 3 \cdot 10^5\), \(1 \le a \le 10^9\)) — the number of proposed tasks and the profit for a single problem, respectively.

Each of the next \(n\) lines contains two integers \(d_i\) and \(c_i\) (\(1 \le d_i, c_i \le 10^9, d_i < d_{i+1}\)).

Output

Print one integer — maximum amount of burles Vasya can earn.

Sample Input:

5 10

1 15

5 3

6 11

7 2

11 22

Sample Output:

13

Sample Input:

3 5

1 8

2 19

3 11

Sample Output:

0

题目链接

题解:

你现在有一个题库,里面有\(n\)道题,每道题难度为\(d_i\), 保证\(d_i\)严格单调增,你现在需要从中选择出一个连续子段的题来组成一场比赛,比赛每有一道题你能获得\(a\)的收益,但需要给作者支付\(c_i\)的费用,除此以外,你还需要支付相邻两道题的难度的差值的平方的最大值的费用(可能题目难度跨度过大会引起不满233)

形式话的说,如果你选择了\(l\)到\(r\)的题目,最后总收益为\(a \cdot (r-l+1)-\sum_l^rc_i-\max\limits_{l\le i\lt r}(d[i+1]-d[i])^2\), 特别地如果\(l=r\),则第三项为0

首先考虑前两项,显然每道题的收益为\(a-c_i\),如果没有第三项那就是一个最大子段和问题

现在考虑第三项,设\(diff[i] = d[i + 1] - d[i]\),只有\(n-1\)项,考虑这\(n-1\)项分别作为最大值的的区间,就是左边下标最大的比它大的和右边下标最小的比它大的中间的区间即为\(diff[i]\)作为最大值的区间,这个可以用单调栈\(O(n)\)处理出来,然后用线段树跑\(n-1\)次最大子段和就行了,总复杂度为\(O(nlog(n))\)

ps:这里有一个问题,就是对于\(diff[i]\)跑最大子段和时跑出来的区间不一定包含\(i\),但这题不是问题,因为要减去\(diff[i]^2\),不包含的话只会获得更小的值(设该区间\(diff\)最大值为\(diff[j]\),显然\(diff[j] \le diff[i]\),在处理以\(diff[j]\)为最大值的区间时可以获得更大的收益),如果一定要包含那就线段树改成询问\(l\)到\(i\)的包含右端点的最大值和\(i+1\)到\(r\)的包含左端点的最大值(可以为空)加起来就行了

pps:还有就是整场比赛只有一道题(没有\(diff\)),直接\(O(n)\)处理出来就行了

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 3e5 + 10; struct tree {
LL sum, rmx, lmx, mx;
}sgt[N << 2]; int c[N], d[N], diff[N], a, n, l[N], r[N];
long long ans; void pushup(int rt) {
sgt[rt].sum = sgt[rt << 1].sum + sgt[rt << 1 | 1].sum;
sgt[rt].mx = max(sgt[rt << 1].mx, sgt[rt << 1 | 1].mx);
sgt[rt].lmx = max(sgt[rt << 1].lmx, sgt[rt << 1].sum + sgt[rt << 1 | 1].lmx);
sgt[rt].rmx = max(sgt[rt << 1 | 1].rmx, sgt[rt << 1 | 1].sum + sgt[rt << 1].rmx);
sgt[rt].mx = max(sgt[rt].mx, sgt[rt << 1].rmx + sgt[rt << 1 | 1].lmx);
} void build(int rt, int l, int r) {
if(l == r) {
sgt[rt].sum = sgt[rt].lmx = sgt[rt].rmx = sgt[rt].mx = c[l];
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
} tree query(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) return sgt[rt];
int mid = l + r >> 1;
if(R <= mid) return query(rt << 1, l, mid, L, R);
if(L > mid) return query(rt << 1 | 1, mid + 1, r, L, R);
tree u = query(rt << 1, l, mid, L, R), v = query(rt << 1 | 1, mid + 1, r, L, R), o;
o.sum = u.sum + v.sum;
o.mx = max(u.mx, v.mx);
o.mx = max(o.mx, u.rmx + v.lmx);
o.lmx = max(u.lmx, u.sum + v.lmx);
o.rmx = max(v.rmx, v.sum + u.rmx);
return o;
} struct node {
int val, id;
}; int main() {
scanf("%d %d", &n, &a);
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &d[i], &c[i]);
c[i] = a - c[i];
ans = max(ans, 1LL * c[i]);
}
for(int i = 1; i < n; ++i)
diff[i] = d[i + 1] - d[i];
build(1, 1, n);
stack<node> stk;
stk.push({(int)1e9, 0});
for(int i = 1; i < n; ++i) {
while(stk.top().val <= diff[i])
stk.pop();
l[i] = stk.top().id + 1;
stk.push({diff[i], i});
}
while(!stk.empty()) stk.pop();
stk.push({(int)1e9, n});
for(int i = n - 1; i; --i) {
while(stk.top().val <= diff[i])
stk.pop();
r[i] = stk.top().id;
stk.push({diff[i], i});
}
for(int i = 1; i < n; ++i) {
ans = max(ans, query(1, 1, n, l[i], r[i]).mx - 1LL * diff[i] * diff[i]);
}
printf("%lld\n", ans);
return 0;
}

Codeforces 1107G Vasya and Maximum Profit 线段树最大子段和 + 单调栈的更多相关文章

  1. [Educational Round 59][Codeforces 1107G. Vasya and Maximum Profit]

    咸鱼了好久...出来冒个泡_(:з」∠)_ 题目连接:1107G - Vasya and Maximum Profit 题目大意:给出\(n,a\)以及长度为\(n\)的数组\(c_i\)和长度为\( ...

  2. CodeForces 1107 - G Vasya and Maximum Profit 线段树

    题目传送门 题解: 枚举 r 的位置. 线段树每个叶子节点存的是对应的位置到当前位置的价值. 每次往右边移动一个r的话,那么改变的信息有2个信息: 1. sum(a-ci) 2.gap(l, r) 对 ...

  3. Codeforces 1107G Vasya and Maximum Profit [单调栈]

    洛谷 Codeforces 我竟然能在有生之年踩标算. 思路 首先考虑暴力:枚举左右端点直接计算. 考虑记录\(sum_x=\sum_{i=1}^x c_i\),设选\([l,r]\)时那个奇怪东西的 ...

  4. Codeforces 1383E - Strange Operation(线段树优化 DP or 单调栈+DP)

    Codeforces 题目传送门 & 洛谷题目传送门 Yet another 自己搞出来的难度 \(\ge 2800\) 的题 介绍一个奇奇怪怪的 \(n\log n\) 的做法.首先特判掉字 ...

  5. Codeforces 487B Strip (ST表+线段树维护DP 或 单调队列优化DP)

    题目链接 Strip 题意   把一个数列分成连续的$k$段,要求满足每一段内的元素最大值和最小值的差值不超过$s$, 同时每一段内的元素个数要大于等于$l$, 求$k$的最小值. 考虑$DP$ 设$ ...

  6. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  7. [Codeforces 280D]k-Maximum Subsequence Sum(线段树)

    [Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...

  8. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

  9. AcWing:245. 你能回答这些问题吗(线段树最大子段和)

    给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤ymaxx≤l≤r≤y{∑ri=lA[i]∑i=l ...

随机推荐

  1. hadoop 根据secondary namenode恢复namenode

    refer to http://www.cnblogs.com/Richardzhu/p/3435989.html http://blog.csdn.net/wuzhilon88/article/de ...

  2. Python 列表解析list comprehension和生成表达式generator expression

    如果想通过操作和处理一个序列(或其他的可迭代对象)来创建一个新的列表时可以使用列表解析(List comprehensions)和生成表达式(generator expression) (1)list ...

  3. Linux平台下贪吃蛇游戏的运行

    1.参考资料说明: 这是一个在Linux系统下实现的简单的贪吃蛇游戏,同学找帮忙,我就直接在Red Hat中调试了一下,参考的是百度文库中"maosuhan"仁兄的文章,结合自己的 ...

  4. 【leetcode刷题笔记】Next Permutation

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  5. 剑指offer之 从尾到头打印链表

    package Problem5; import java.util.Stack; //首先定义链表结构class LinkNode{ LinkNode next; int node_value;} ...

  6. 算法(Algorithms)第4版 练习 2.1.25

    代码实现: package com.qiusongde; import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.StdOut; ...

  7. python循环切片

    x = [0,99, 'a', 1, 2, 'b',5, 3, 0,'a' ,1, 8, 5,'b',5,9,5] b=[] c=[] d=[] for i in range(len(x)): if ...

  8. github之克隆

    git clone --depth=10 git_仓库_url 只会获取最近 xx(10条提交记录的)代码,默认是master分支, 如果想要指定分支,可以结合 -b --single--branch ...

  9. Spring MVC工作原理(好用版)

    Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...

  10. Struts2 第一个入门小案例

    1.加载类库 2 配置web.xml文件 3.开发视图层 4.开发控制层Action 5.配置struts.xml 6.部署运行