题解:洛谷 P4231 三步必杀

洛谷 P4231 三步必杀

题意

\(n\) 个位置,有 \(m\) 次操作,每次操作如下:

  • \([l,r]\) 内的位置加上对应的以 \(s\) 为开头,\(e\) 为末尾的等差数列的对应位置。

求所有操作后每个位置上的值。

\(n\le10^7\)\(m\le3\times10^5\)

解法

绝世好题!二阶差分!

对于这种区间求和的问题,很容易想到差分。

考虑先求出公差 \(d=\dfrac{e-s}{r-l}\)

下面是差分的修改:

\(l\) \(l+1\) \(\cdots\) \(r-1\) \(r\) \(r+1\)
\(+s\) \(+d\) \(+d\) \(+d\) \(+d\) \(-e\)

但是显然这样需要区间加,直接差分维护需要带 \(\log\) 的数据结构。

考虑将中间的 \(+d\) 消除,可以发现 \((+d)-(-d)=0\),那么可以试着再做一次差分(考虑差分的定义就可以得到):

\(l\) \(l+1\) \(\cdots\) \(r\) \(r+1\) \(r+2\)
\(+s\) \(+d-s\) \(0\) \(0\) \(-e-d\) \(+e\)

这样可以发现中间变为了 \(0\),只需要对 \(l,l+1,r+1,r+2\) 的位置进行修改即可,这样单次复杂度即为 \(O(1)\)

时间复杂度

  • 遍历每一操作,\(O(m)\)
    • 单次操作,\(O(1)\)

时间复杂度 \(O(m)\),可以通过。

代码

/**
 * Problem: P4231 三步必杀
 * Author:  OIer_wst
 * Date:    2025-07-09
 */
#include <bits/stdc++.h>
using lint = long long;

int main() {
  std::cin.tie(0)->sync_with_stdio(0);
  int n, m; std::cin >> n >> m;
  std::vector<lint> a(n + 3);
  for (lint l, r, s, e; m; --m) {
    std::cin >> l >> r >> s >> e;
    lint d = (e - s) / (r - l);
    a[l] += s;
    a[l + 1] += d - s;
    a[r + 1] += -e - d;
    a[r + 2] += e;
  }
  for (int i = 1; i <= n; ++i) a[i] += a[i - 1];
  lint ans = 0, mx = 0;
  for (int i = 1; i <= n; ++i) {
    a[i] += a[i - 1];
    ans ^= a[i];
    mx = std::max(mx, a[i]);
  }
  std::cout << ans << " " << mx << std::endl;
  return 0;
}
posted @ 2025-07-09 19:50  OIer_wst  阅读(25)  评论(0)    收藏  举报