嘘~ 正在从服务器偷取页面 . . .

CF1406D Three Sequences 题解


CF1406D Three Sequences 题解

题目链接:Three Sequences

题意

给定一个序列$a_1,a_2,\ldots ,a_n$,长度为 $n$ 的序列 $b,c$ 符合以下条件

  1. $a_i=b_i+c_i$
  2. $b$ 为不下降序列,$c$ 为不上升序列,即 $b_i\geq b_{i-1}, c_i\leq c_{i-1}$

有 $q$ 个操作,每次操作可以把 $[l,r]$ 的数增加 $x$。求每次操作后最小的 $\max(b_i,c_i)$ 。

输入格式

第一行包含一个整数 $n$($1\leq n\leq 10^5$)。

第二行包含 $n$ 个整数 $a_1,a_2,\ldots,a_n$($1\leq i\leq n$,$-10^9\leq a_i\leq 10^9$)。

第三行包含一个整数 $q$($1\leq q\leq 10^5$)。

接下来的每行(共 $q$ 行)包含三个整数 $l,r,x$($1\leq l\leq r\leq n, -10^9\leq x\leq 10^9$),描述了下一次的操作。

输出格式

输出 $q+1$ 行。

在第 $i$ 行($1 \leq i \leq q+1$),打印经过 $i-1$ 次变化后序列的问题答案。

容易发现以下两个性质

  • 对于序列中的升序,一定由 $c_i$ 来实现,$b_i$ 保持全相等;降序则由 $b_i$ 实现, $c_i$​ 保持全相等。
  • $b_i$ 中的最大值为 $b_n$ ,$c_i$ 中的最大值为 $c_1$ ,则 $\max \left\{b_n, c_1\right\}=\left\lceil\frac{b_n+c_1}{2}\right\rceil$

由性质2亦可知

因为 $b_1+c_1=a_1$ ,记 $d_i = b_i - b_{i-1}$ ,则 $d_i = \left(a_i-a_{i-1}\right) \times\left[a_i \geq a_{i-1}\right]$ ,这可以预处理出来。

于是我们对于没有修改的情况已经得到答案了,而修改是区间加法使得我们可以用树状数组轻松维护。

时间复杂度 $\mathcal{O}(q \log n)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))

int n, q, a[N], d[N], tr[N];
int lowbit(int x) { return x & (-x); }
void add(int x, int v) { for(int i = x; i && i <= n; i += lowbit(i)) tr[i] += v; }
int sum(int x, int r = 0) { for(int i = x; i; i -= lowbit(i)) r += tr[i]; return r; }
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n; int S = 0;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 2; i <= n; i++) d[i] = (a[i] - a[i - 1]) * (a[i] >= a[i - 1]);
    for(int i = 2; i <= n; i++) S += d[i];
    cout << (int)ceil((a[1] + S) * 1.0 / 2) << '\n';
    cin >> q;
    for(int l, r, v; q--; )
    {
        cin >> l >> r >> v; add(l, v); add(r + 1, -v);
        int x = a[l - 1] + sum(l - 1), y = a[l] + sum(l);
        if(l > 1) { S -= d[l]; d[l] = (y - x) * (y >= x); S += d[l]; }
        x = a[r] + sum(r), y = a[r + 1] + sum(r + 1);
        if(r < n) { S -= d[r + 1]; d[r + 1] = (y - x) * (y >= x); S += d[r + 1]; }
        cout << (int)ceil((a[1] + sum(1) + S) * 1.0 / 2) << '\n';
    }
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/y5owwe89


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录