1 条题解
-
0
题意
给定一个长度为 的排列 (下标从 开始)。
定义一次“霸凌交换”如下:. 找到最大的元素 使得 (即最右边的不在正确位置的元素),记其下标为 。 . 找到最小的元素 满足 (即在 右边的最小元素),记其下标为 。 . 交换 和 。
重复执行直到排列变为 。记 为所需的交换次数。
初始时若已是恒等排列,则 。现在有 次更新,每次交换 和 (),每次更新后输出新的 。
更新是持久化的,即每次交换会改变排列。
关键结论
经过分析,霸凌交换的过程等价于:
- 每次操作会将当前最右边的错位元素( 中最大的 )放到它正确的位置,同时把右边最小的元素移到左边。
- 最终, 可以分解为两部分:$$f(p) = \sum_{i: p_i > i} (p_i - i) + \sum_{i: p_i < i} 1
$$即:
- 所有 的元素需要向右移动 步
- 所有 的元素每个贡献
因此,我们只需要维护这两个部分的和。
数据结构
设:
则 。
当交换 和 ()时,只有位置 和 的贡献会改变。
我们可以用树状数组(BIT)来维护哪些位置满足 (即这些位置在 BIT 中为 ,其余为 ),从而 。同时, 用一个变量直接维护。
更新操作
设交换前:
- ,
步骤 :减去旧贡献
对于位置 :
- 若 : 减去
- 若 :BIT 在 处减
对于位置 :
- 若 : 减去
- 若 :BIT 在 处减
步骤 :交换值
swap(p[x], p[y]); swap(pos[a], pos[b]);步骤 :加上新贡献
现在新的 ,。
对于位置 :
- 若 : 加上
- 若 :BIT 在 处加
对于位置 :
- 若 : 加上
- 若 :BIT 在 处加
步骤 :输出答案
复杂度
- 预处理
- 每次更新 (BIT 操作)
- 总复杂度 ,可过 ,
完整代码
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 5e5 + 5; int n, q; int p[N], pos[N]; ll ans = 0; struct BIT { int tree[N]; void add(int i, int x) { for (; i <= n; i += i & -i) tree[i] += x; } int sum(int i) { int s = 0; for (; i; i -= i & -i) s += tree[i]; return s; } int range(int l, int r) { return sum(r) - sum(l - 1); } } bit; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> q; for (int i = 1; i <= n; i++) { cin >> p[i]; pos[p[i]] = i; if (p[i] > i) ans += p[i] - i; else if (p[i] < i) bit.add(i, 1); } auto update = [&](int x, int y) { // 交换 p[x] 和 p[y] int a = p[x], b = p[y]; // 更新答案 // 先减去旧贡献 if (a > x) ans -= a - x; else if (a < x) bit.add(x, -1); if (b > y) ans -= b - y; else if (b < y) bit.add(y, -1); swap(p[x], p[y]); swap(pos[a], pos[b]); // 加上新贡献 if (a > y) ans += a - y; else if (a < y) bit.add(y, 1); if (b > x) ans += b - x; else if (b < x) bit.add(x, 1); }; while (q--) { int x, y; cin >> x >> y; if (x > y) swap(x, y); update(x, y); cout << ans + bit.sum(n) << "\n"; } return 0; }
示例验证
输入:
8 5 6 2 1 5 3 4 7 8 1 8 2 3 4 7 7 8 3 6输出:
5 6 9 8 7与题目样例一致。
总结
- 将 转化为可维护的形式:$f(p) = \sum_{p_i > i} (p_i - i) + \#\{i \mid p_i < i\}$
- 用变量 维护第一部分,用 BIT 维护第二部分
- 每次交换只影响两个位置, 更新
- 1
信息
- ID
- 7196
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 1
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者