Gifts Order

题目大意

给定 \(1 \le n \le 2 \times 10^5\) 以及一个序列 \(a\).

现在有 \(1 \le q \le 2 \times 10^5\) 次修改, 每次将 \(a_p \gets x\), 你需要最大化下面的式子:

\[f(l, r) = \max^r_{i = l}(a_i) - \min^r_{i = l}(a_i) - (r - l) \]

其中 \(1 \le l \le r \le n\).

思路

先抛一个性质: 最大值和最小值一定在答案序列的两端.

证明一下, 如果最小值不在端点上, 那么我们一定可以缩小区间来减小 \((r - l)\) 从而加大 \(f(l, r)\), 最大值也同理.

那这样就好做了, 分两种情况讨论.

  1. 最小值在左, 最大值在右.

    $f(l, r) = a_l - a_r - (r - l) $, 移一下项, \(f(l, r) = a_l + l - a_r - r\).

    这样就可以用线段树维护两个值 \(a_i + i\)\(-a_i - i\) 了.

  2. 最大值在左, 最小值在右.

    同样地, \(f(l, r) = a_r - a_l - (r - l) = a_r - r - a_l + l\), 用线段树维护下 \(a_i - i\)\(-a_i + i\) 即可.

具体可以看实现, 时间复杂度 \(\mathcal{O}((n + q) \log n)\).

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
#include "iostream" #include "algorithm" using namespace std; constexpr int N = 2e5 + 10; int n, q, a[N]; #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r class Segment_Tree { protected: int t1[N << 2], t2[N << 2], t3[N << 2], t4[N << 2]; public: int ans[N << 2]; void update(int rt, int l, int r, int x, int k) { if (l == r) return ans[rt] = 0, t1[rt] = k + l, t2[rt] = -k - l, t3[rt] = k - l, t4[rt] = -k + l, void(); int mid = (l + r) >> 1; if (x <= mid) update(lson, x, k); else update(rson, x, k); ans[rt] = max({ans[rt << 1], ans[rt << 1 | 1], t1[rt << 1] + t2[rt << 1 | 1], t4[rt << 1] + t3[rt << 1 | 1]}); t1[rt] = max(t1[rt << 1], t1[rt << 1 | 1]), t2[rt] = max(t2[rt << 1], t2[rt << 1 | 1]); t3[rt] = max(t3[rt << 1], t3[rt << 1 | 1]), t4[rt] = max(t4[rt << 1], t4[rt << 1 | 1]); } } st; void init() { scanf("%d %d", &n, &q); for (int i = 1; i <= n; ++i) scanf("%d", a + i), st.update(1, 1, n, i, a[i]); } void calculate() { printf("%d\n", st.ans[1]); while (q--) { int p, x; scanf("%d %d", &p, &x); st.update(1, 1, n, p, x); printf("%d\n", st.ans[1]); } } void solve() { init(); calculate(); } int main() { int t; scanf("%d", &t); while (t--) solve(); return 0; }
posted @   Steven1013  阅读(15)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开