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. 在Treeview中节点的data属性中保存记录类型及其消除的办法

    一.保存记录类型在data指针中: procedure TForm1.getheaditems(pp:TfrxBand;hnode:THeadTreeNode;var i:Integer;var j: ...

  2. Java -- Swing 组件使用

    1. 示例1 public class Main { JFrame f = new JFrame(); Icon okIcon = new ImageIcon("/home/test/sta ...

  3. Spring- 异常org.xml.sax.SAXParseException; systemId: http://www.springframework.org/schema/context/; lineNumber: 1; columnNumber: 55; 在 publicId 和 systemId 之间需要有空格。

    抛出异常 六月 03, 2018 7:40:44 下午 org.springframework.context.support.AbstractApplicationContext prepareRe ...

  4. vs2015配置boost c++

    参考:https://blog.csdn.net/zengraoli/article/details/70187556 https://blog.csdn.net/misterfm/article/d ...

  5. iis常见问题解决

    iis7以上版本部署4.0框架项目常见问题解决 配置错误: 不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况.锁定是默认设置的 (overrideModeDefault=&quo ...

  6. Delphi - 数组 详解

    技术交流,DH讲解. 首先我们要知道什么是数组?数组是一堆相同特性数据的一个集合,也就是每个元素的类型必须是一样的,当然在其他一些弱语法的语言里面,数组的元素可以千奇百怪. 例子: ? 1 2 3 4 ...

  7. csv+jenkins+ant测试接口

    1.文件目录 jmeter_test case 用于存放case,csv或者txt格式,jmeter能读取的 result_log 用于存放报告 html 存放html报告 jtl 存放jtl文件 s ...

  8. MySQL--开发技巧(一)

    Inner Join: Left Outer Join: Right Outer Join: Full Join: Cross Join: SELECT t1.attrs ,t2.attrs FROM ...

  9. 了解fiddler:实现简单的抓包测试

    fiddler是一款轻型的抓包软件 本文介绍几个常用的功能:(相信图片更直观点,上图片,右键在新标签页中打开,查看高清大图) 通过composer,我们可以修改http头部信息,修改post(),ge ...

  10. codeforces 515C C. Drazil and Factorial(水题,贪心)

    题目链接: C. Drazil and Factorial time limit per test 2 seconds memory limit per test 256 megabytes inpu ...