NSDY 似乎的 polylog 做法

似乎在随机下比较快,可以卡。

\[\sum_{i=l}^r \sum_{j=i}^r |x_i-x_j| + |y_i-y_j|\\ \]

我们把贡献拆开,得到:

\[\sum_{1 \le i < j \le r} |x_i-x_j|+\sum_{1 \le i < j \le r} |x_i-x_j|\\ \]

先拆维,然后比如考虑维护 \(x\) 轴。

\[\sum_{1 \le i < j \le r} |x_i-x_j|\\ =\sum_{1 \le i < j \le r} |x_i-x_j|-\sum_{1 \le i < j \le l-1} |x_i-x_j|-\sum_{i=1}^{l-1} \sum_{j=l}^r |x_i-x_j|\sum_{1 \le i < j \le r} |x_i-x_j|\\ =\sum_{1 \le i < j \le r} |x_i-x_j|-\sum_{1 \le i < j \le l-1} |x_i-x_j|-\sum_{i=1}^{l-1} \sum_{j=l}^r |x_i-x_j|\\ = F(r) - F(l-1) - G(l,r) \]

其中 \(F(r)=\sum_{1\le i<j\le r}|x_i-x_j|\) 可预处理,\(G(l,r)=\sum_{i=1}^{l-1}\sum_{j=l}^r |x_i-x_j|\) 是需要在线维护的核心。

预处理 \(F(r)\)

使用两个树状数组(或线段树)维护值域上的个数和总和。从左到右扫描 \(r\),每次加入 \(x_r\),计算它与前面所有点的距离和:

\[\text{贡献} = x_r \cdot \text{cntL} - \text{sumL} + \text{sumG} - x_r \cdot \text{cntG}, \]

其中 \(\text{cntL}\)\(\text{sumL}\) 是前面小于等于 \(x_r\) 的个数与和,\(\text{cntG}=r-1-\text{cntL}\)\(\text{sumG}=\text{前缀和}-\text{sumL}\)。累加得到 \(F(r)\),复杂度 \(O(n\log n)\)

维护 \(G(l,r)\)

采用离线扫描左端点 \(l\),并维护一个线段树,每个位置 \(j\) 存储当前值 \(\text{val}_j = \sum_{i=1}^{l-1} |x_i - x_j|\)。初始时 \(l=1\),所有 \(\text{val}_j=0\)

\(l\) 增加时(即加入新左边点 \(x_l\)),需要对所有 \(j>l\) 更新:\(\text{val}_j \leftarrow \text{val}_j + |x_j - x_l|\)。这个操作需要高效处理,因为 \(|x_j-x_l|\) 依赖于 \(x_j\)\(x_l\) 的大小关系。

线段树设计

每个节点维护以下信息:

  • \(sum\):区间内 \(\text{val}\) 的和。
  • \(sum_x\):区间内原始 \(x\) 值的和。
  • \(max_x, min_x\):区间内原始 \(x\) 的最大最小值。
  • \(len\):区间长度。
  • 懒标记:\(add\_self\)(每个位置加上自身 \(x\) 的次数),\(add\_const\)(加上常数的累加值)。

更新操作 \(\text{update}(l, r, c)\) 表示对区间 \([l,r]\) 内每个位置加上 \(|x_j - c|\)。递归处理:

  • 若当前节点区间完全在更新范围内:
    • 如果 \(max_x \le c\),则整个区间应加 \(c - x_j\),即 \(add\_const += c\)\(add\_self -= 1\),同时 \(sum += c \cdot len - sum_x\)
    • 如果 \(min_x \ge c\),则整个区间应加 \(x_j - c\),即 \(add\_const -= c\)\(add\_self += 1\),同时 \(sum += sum_x - c \cdot len\)
    • 否则,递归到左右子节点。
  • 若部分重叠,同样递归。

查询时,下推标记后返回区间和。

扫描过程

将所有查询按 \(l\) 分组。对于 \(l=1\)\(n\)

  1. 处理所有左端点为 \(l\) 的查询:得到 \(G(l,r)\) = 线段树区间 \([l,r]\)\(sum\)
  2. \(l<n\),执行 \(\text{update}(l+1, n, x_l)\)

答案合成

对于每个查询,一维答案为:

\[\text{ans}_x = F(r) - F(l-1) - G(l,r). \]

\(y\) 维同样处理,最终答案 \(\text{ans} = \text{ans}_x + \text{ans}_y\)

复杂度

  • 预处理 \(F\)\(O(n\log n)\)
  • 线段树每个更新和查询期望 \(O(\log n)\),总复杂度 \(O((n+q)\log n)\)(实际性能依赖于数据,但可通过节点标记优化)。

此方法利用线段树的分治特性,将动态更新转化为区间标记,实现了对 \(G(l,r)\) 的高效维护。

本人题解:

\[\sum_{i=l}^r \sum_{j=i}^r |x_i-x_j| + |y_i-y_j|\\ \]

我们把贡献拆开,得到:

\[\sum_{1 \le i < j \le r} |x_i-x_j|+\sum_{1 \le i < j \le r} |x_i-x_j|\\ \]

先拆维,然后比如考虑维护 \(x\) 轴。

\[\sum_{1 \le i < j \le r} |x_i-x_j|\\ =\sum_{1 \le i < j \le r} |x_i-x_j|-\sum_{1 \le i < j \le l-1} |x_i-x_j|-\sum_{i=1}^{l-1} \sum_{j=l}^r |x_i-x_j|\sum_{1 \le i < j \le r} |x_i-x_j|\\ =\sum_{1 \le i < j \le r} |x_i-x_j|-\sum_{1 \le i < j \le l-1} |x_i-x_j|-\sum_{i=1}^{l-1} \sum_{j=l}^r |x_i-x_j| \]

对于区间 \([l, r]\) 内的 \(k\) 个点(设 \(k = r-l+1\)),我们将该维度的坐标提取出来并升序排列为 \(a_1 \le a_2 \le \dots \le a_k\)。那么我们有:

\[\sum_{1 \le i < j \le k} (a_j - a_i)\\ = \sum_{i=1}^k (2i - 1 - k) \cdot a_i\\ = 2 \cdot \left( \sum_{i=1}^k i \cdot a_i \right) - (k+1) \cdot \left( \sum_{i=1}^k a_i \right) \]

且有

\[\sum_{j=1}^r i \cdot x_j\\ =\sum_{j=1}^r x_j \cdot \left( \sum_{p=1}^r [x_p \le x_j] \right)\\ \]

后半部分是简单的,考虑维护前半部分。

这是一个经典的二维偏序贡献问题。为了消去区间 \([l, r]\) 的左端点 \(l\) 的限制,我们使用离线扫描线,考虑维护一个数组 \(f_r=\sum_{j=1}^r i \cdot x_j\\\)。现在我们求出了 \(f_{r-1}\),看如何转移到 \(f_r\)。我们发现有两部分贡献,第一个是 \(x_r\) 系数的大小产生的,第二个是 \(x_r\) 对其他点系数产生的变化。我们可以用两个 BIT。一个是前缀所有值的和,另一个是前缀所有值的个数。然后分别把答案算上就好了。

然后来考虑维护 \(\sum_{i=1}^{l-1} \sum_{j=l}^r |x_i-x_j|\),然后这个东西是做不了 polylog 的,结束了,这个题有莫队简单写法 link

posted @ 2026-02-23 20:37  NeeDna  阅读(1)  评论(0)    收藏  举报