@description@

给定序列 T1, T2, ... TN,你可以从中选择一些 Ti,可以选择 0 个(即不选)。

定义你选择的权值 = (满足 T[L...R] 都被选择的区间 [L, R] 的数量)-(你选择的 Ti 之和),你希望这个权值尽量大。

现在有 M 次询问,每次询问假如将 T[Pi] 修改成 Xi,你所能选出的最大权值。

Constraints

1 <= N, M <= 3*10^5,1 <= Ti <= 10^9 且所有 Ti 总和 <= 10^12。

对于每组询问,满足 1 <= Pi <= N,1 <= Xi <= 10^9。

Input

输入形式如下:

N

T1 T2 … TN

M

P1 X1

P2 X2

:

PM XM

Output

对于每组询问,输出其答案。

Sample Input 1

5

1 1 4 1 1

2

3 2

3 10

Sample Output 1

9

2

@solution@

考虑在修改 T[Pi] 为 Xi 后,最后的选择方案要么包含 Pi 要么不包含。

假如不包含,则只需要在 1 ... Pi - 1 与 Pi + 1 ... N 中选择得到最大值。

假如包含,我们需要预处理包含 Pi 的最优解,然后用这个最优解 + T[Pi] - Xi。

综上,我们需要处理出三个东西:第一个 f[i] 表示从 1 ... i 中选择的最优答案,第二个 g[i] 表示从 i ... N 中选择的最优答案,第三个 h[i] 表示必须选择 i 的最优答案。

先一步步考虑,考虑求 f[i]。要么不选 i 从 f[i-1] 转移过来;要么选择 i,我们枚举一个 j 表示我们强制选择 i + 1 ... j 中的所有数,则贡献为 f[j] + ([i + 1, j] 中的区间数量)-([i + 1, j] 的 T 值之和)。

通过预处理前缀和 S[i] = T[1] + T[2] + ... T[i],可以将转移式写得更具体一点:

\[f[i] = \max(f[i-1], \max_{0\le j<i}(f[j] + S[j] - S[i] + \frac{(i-j+1)*(i-j)}{2}))
\]

上面那个转移非常斜率优化,稍微变化一下式子发现的确可以斜率优化。这里就不具体写了。

总之,这个式子是个斜率单增且横坐标单增的斜率优化,可以使用单调栈做到 O(n) 的时间复杂度。

而 g[i] 可以类似地处理。这里也不具体谈了。

现在考虑怎么求 h[i]。最暴力的方法是在 i 左边枚举一个左端点 l,i 右边枚举一个右端点 r,算出区间 [l, r] 的贡献再加上 f[l - 1] + g[r + 1]。

考虑优化,我们发现 cdq 分治非常合适(其实我也不知道它该不该叫作cdq分治,只是感觉比较像)。

对于区间 [left, right],设它的中点为 mid,我们仅考虑满足 left <= l <= mid < r <= right 的区间 [l, r] 对 h[l...r] 的贡献。

然后递归到 [left, mid] 与 [mid + 1, right],继续处理子问题,直到 left = right。

怎么处理呢?我们先将 [left, mid] 的点加入单调栈;然后从左往右扫 [mid + 1, right] 用斜率优化求出 [mid + 1, right] 内所有点作为右端点的答案;然后再从右往左扫描,扫到 x 时维护出 [x, right] 的最大值 tmp,用这个 tmp 更新 h[x]。

再反过来将 [mid + 1, right] 加入单调栈,更新 [left, mid] 的 h 值。这个过程与上面类似,不再赘述。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 300000;
const ll INF = (1LL<<60);
ll f[MAXN + 5], g[MAXN + 5], h[MAXN + 5];
ll S[MAXN + 5], T[MAXN + 5];
ll fk(int i) {return i;}
ll fx(int j) {return 2LL*j;}
ll fc(int i) {return 1LL*i*i + i - 2*S[i];}
ll fy(int j) {return 2*S[j] + f[j] - j + 1LL*j*j;}
double fslope(int p, int q) {return 1.0*(fy(q) - fy(p)) / (fx(q) - fx(p));}
ll gk(int i) {return -i;}
ll gx(int j) {return -2LL*j;}
ll gc(int i) {return 1LL*i*i - i + 2*S[i-1];}
ll gy(int j) {return -2*S[j-1] + g[j] + j + 1LL*j*j;}
double gslope(int p, int q) {return 1.0*(gy(q) - gy(p)) / (gx(q) - gx(p));}
int stk[MAXN + 5], tp;
int N, M;
void get_dp() {
f[0] = 0; stk[tp = 1] = 0;
for(int i=1;i<=N;i++) {
while( tp > 1 && fk(i) >= fslope(stk[tp], stk[tp-1]) )
tp--;
f[i] = max(f[i - 1], fc(i) - fk(i)*fx(stk[tp]) + fy(stk[tp]));
while( tp > 1 && fslope(i, stk[tp]) >= fslope(stk[tp], stk[tp-1]) )
tp--;
stk[++tp] = i;
}
g[N + 1] = 0; stk[tp = 1] = N + 1;
for(int i=N;i>=1;i--) {
while( tp > 1 && gk(i) >= gslope(stk[tp], stk[tp-1]) )
tp--;
g[i] = max(g[i + 1], gc(i) - gk(i)*gx(stk[tp]) + gy(stk[tp]));
while( tp > 1 && gslope(i, stk[tp]) >= gslope(stk[tp], stk[tp-1]) )
tp--;
stk[++tp] = i;
}
}
ll tmp[MAXN + 5];
void divide_conquer(int l, int r) {
if( l == r ) {
h[l] = f[l + 1] - 2*T[l] + g[r + 1] + 2;
return ;
}
int mid = (l + r) >> 1;
divide_conquer(l, mid);
divide_conquer(mid + 1, r);
stk[tp = 1] = l - 1;
for(int i=l;i<mid;i++) {
while( tp > 1 && fk(i) >= fslope(stk[tp], stk[tp-1]) )
tp--;
while( tp > 1 && fslope(i, stk[tp]) >= fslope(stk[tp], stk[tp-1]) )
tp--;
stk[++tp] = i;
}
for(int i=mid+1;i<=r;i++) {
while( tp > 1 && fk(i) >= fslope(stk[tp], stk[tp-1]) )
tp--;
tmp[i] = fc(i) - fk(i)*fx(stk[tp]) + fy(stk[tp]) + g[i + 1];
}
ll p = -INF;
for(int i=r;i>mid;i--) {
p = max(p, tmp[i]);
h[i] = max(h[i], p);
}
stk[tp = 1] = r + 1;
for(int i=r;i>mid+1;i--) {
while( tp > 1 && gk(i) >= gslope(stk[tp], stk[tp-1]) )
tp--;
while( tp > 1 && gslope(i, stk[tp]) >= gslope(stk[tp], stk[tp-1]) )
tp--;
stk[++tp] = i;
}
for(int i=mid;i>=l;i--) {
while( tp > 1 && gk(i) >= gslope(stk[tp], stk[tp-1]) )
tp--;
tmp[i] = gc(i) - gk(i)*gx(stk[tp]) + gy(stk[tp]) + f[i - 1];
}
p = -INF;
for(int i=l;i<=mid;i++) {
p = max(p, tmp[i]);
h[i] = max(h[i], p);
}
}
int main() {
scanf("%d", &N);
for(int i=1;i<=N;i++)
scanf("%lld", &T[i]), S[i] = S[i - 1] + T[i];
get_dp(), divide_conquer(1, N);
scanf("%d", &M);
for(int i=1;i<=M;i++) {
int P, X; scanf("%d%d", &P, &X);
printf("%lld\n", max(f[P-1] + g[P+1], h[P] + 2*T[P] - 2*X)/2);
}
}

@details@

h[i] 值是必须要包含 i 的,所以可能为负数,给 h 初始化时应该赋值为 -inf。

话说现在 atcoder 都不办 ARC 了,ARC 已经成为了时代的眼泪。。。

@atcoder - ARC066F@ Contest with Drinks Hard的更多相关文章

  1. [arc066f]Contest with Drinks Hard

    题目大意: 有一些物品,每个买了有代价. 如果存在一个极大区间[l,r]内的物品都被买了,这个区间长度为k,可以获得的收益是k*(k+1)/2. 现在若干次询问,每次问假如修改了某个物品的价格,最大收 ...

  2. AtCoder Beginner Contest 050 ABC题

    A - Addition and Subtraction Easy Time limit : 2sec / Memory limit : 256MB Score : 100 points Proble ...

  3. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  4. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  5. AtCoder Regular Contest 094 (ARC094) CDE题解

    原文链接http://www.cnblogs.com/zhouzhendong/p/8735114.html $AtCoder\ Regular\ Contest\ 094(ARC094)\ CDE$ ...

  6. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  7. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  8. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

  9. AtCoder Grand Contest 009

    AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...

随机推荐

  1. mybatis深入理解(七)-----MyBatis缓存机制的设计与实现

    缓存设计 MyBatis将数据缓存设计成两级结构,分为一级缓存.二级缓存: 一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存.一级缓存是 ...

  2. Django+小程序技术打造微信小程序助手

    Django+小程序技术打造微信小程序助手   整个课程都看完了,当前这个课程的分享可以往下看,下面有某盘的链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,同时也分享下自己的总结 ...

  3. Leetcode54. Spiral Matrix螺旋矩阵

    给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素. 示例 1: 输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ...

  4. Leetcode628.Maximum Product of Three Numbers三个数的最大乘积

    给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积. 示例 1: 输入: [1,2,3] 输出: 6 示例 2: 输入: [1,2,3,4] 输出: 24 注意: 给定的整型数组长度 ...

  5. LUOGU 1278 单词游戏

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  6. toString方法和valueof()方法的区别

    JavaScript引用类型之Array数组的toString()和valueof()方法的区别   一.转换方法 1.在JavaScript中几乎所有对象都具有toLocaleString().to ...

  7. 使用SQLyog将Mysql中的表导出为Excel

    有时会有这样的需求:将MYSQL数据库中的某个表格导出,存为Excel文件.下面介绍步骤: 1.打开SQLyog,选中要导出的表 2.右键--备份/导出--导出表数据作为... 3.如图选择 Exce ...

  8. JS函数式编程 - 概念

    最近在看Typescript,顺便看了一些函数式编程,然后半个国庆假期就没有了.做个笔记,分几个部分写吧. 最开始接触函数式编程的时候,第一个接触的概念就是高阶函数,和柯里化.咋一看,这不就是长期用来 ...

  9. Python 使用BeautifulSoup模块抽取数据

  10. word Stock Market Indices

    Stock Market Indices USA Africa Asia and Pacific Canada Europe Middle East South America Internation ...