[ICPC 2026 APC] Worldwide Playlist
原题链接:https://www.luogu.com.cn/problem/P16568
设 \(p_u\) 为歌曲 \(u\) 在播放列表 \(a\) 中的位置(\(1\) 开始),\(q_i = p_{b_i}\) 为第 \(i\) 首要听的歌曲在 \(a\) 中的位置。
从 \(a\) 的第 \(1\) 首出发,要听到 \(b_1\) 需要跳过 \((q_1-1)\) 次;听完 \(b_1\) 后自动进入 \(q_1\) 的下一首,要听到 \(b_2\) 需要跳过 \((q_2-q_1-1+n)\bmod n\) 次。依此类推,总跳过次数为
把求和展开并抵消中间项,得到简洁公式
其中 \(ans=\bigl|{i\in[2,n]\mid q_i\le q_{i-1}}\bigr|\) 即序列 \(q\) 中“非上升”相邻对的个数。
因此我们只需要只需维护数组 \(q\)(\(q_i\) 为 \(b_i\) 在 \(a\) 中的位置)、末尾值 \(q_n\) 以及计数 \(ans\)。
对于交换 \(a_x,a_y\),只会改变这两首歌的 \(p\) 值,从而在 \(q\) 中恰好改变两个位置(设为 \(i,j\))。先删除这两个位置及其邻居对 \(k\) 的贡献,更新 \(a\) 与 \(p\),等到后面我们再重新计算贡献。然后直接交换 \(b\) 中两个位置的歌曲,\(q_x,q_y\) 随之改变(变为对方原来的 \(p\) 值)。最后重新统计一下这两个位置的逆序对。
对于交换 \(b_x,b_y\),同样先删除受影响的对(\(x\) 与 \(y\) 及其邻居),更新 \(b\) 与 \(q\),再加回贡献。
受影响的下标至多 \(6\) 个,用 set 去重后 \(O(1)\) 维护即可。总复杂度 \(O((n+d)\log n)\)(这里的 \(\log\) 来自小常数的 set )。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
int p[maxn], q[maxn];
int ans = 0;
int pre[maxn];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, d;
cin >> n >> d;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
p[a[i]] = i;
}
for (int i = 1; i <= n; i ++) {
cin >> b[i];
q[b[i]] = i;
}
for (int i = 2; i <= n; i ++) {
if (p[b[i]] < p[b[i - 1]]) ans ++;
}
cout << ans * n - (n - p[b[n]]) << "\n";
d --;
while (d --) {
int c, x, y;
cin >> c >> x >> y;
if (c == 1) { // 替换 a
int i = q[a[x]]; // 替换的数x在b里的下标
int j = q[a[y]]; // 替换的数y在b里的下标
set<int> tmp;
// 受影响的位置,我们一律向前看
if (i > 1) tmp.insert(i);
if (i < n) tmp.insert(i + 1);
if (j > 1) tmp.insert(j);
if (j < n) tmp.insert(j + 1);
// 删掉原本逆序对
for (int e : tmp) {
if (p[b[e - 1]] > p[b[e]]) ans --;
}
// 更换
swap(p[a[x]] ,p[a[y]]);
swap(a[x], a[y]);
// 重新计算逆序对
for (int e : tmp) {
if (p[b[e - 1]] > p[b[e]]) ans ++;
}
cout << ans * n - (n - p[b[n]]) << "\n";
}
else { // 替换b的操作基本一样,这里不再赘述
set<int> tmp;
if (x > 1) tmp.insert(x);
if (x < n) tmp.insert(x + 1);
if (y > 1) tmp.insert(y);
if (y < n) tmp.insert(y + 1);
for (int e : tmp) {
if (p[b[e - 1]] > p[b[e]]) ans --;
}
int u = b[x], v = b[y];
swap(b[x], b[y]);
q[u] = y;
q[v] = x;
for (int e : tmp) {
if (p[b[e - 1]] > p[b[e]]) ans ++;
}
cout << ans * n - (n - p[b[n]]) << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号