闲话

帅炸了。
这是主播被 \(n=1\) 的 case 卡爆了,望周知。
题意
给定长度为 \(n\) 的序列 \(a\),值域为 \([1,n]\),有一些位置未确定。你需要给这些未确定的位置的确定取值,使得序列 \(b_i=a_{a_i}\) 的字典序最小。多测,\(1\leq T\leq 10^5\),\(1\leq n\leq\sum{n}\leq 5\times 10^5\)。
题解
首先特判掉一些 corner case。
若 \(a_1=-1\lor a_1=1\),我们让所有 \(-1\) 的位置都填 \(1\) 显然最优。
若 \(a\) 中恰好有 \(1\) 个 \(-1\) 位于 \(pos\) 处,考虑若存在 \(i\) 使得 \(a_i>i\land a_i=pos\),我们就令 \(a_{pos}\gets 1\);否则我们令 \(a_{pos}\) 为最靠前的全局最小值的位置(注意这里求全局最小值时要先令 \(a_{pos}\gets pos\))。这是因为,如果存在 \(i\) 使得 \(a_i>i\land a_i=pos\),那么 \(b_i\) 要比 \(b_{pos}\) 更靠前,所以我们肯定优先把 \(b_i\) 置为 \(1\);否则我们就要让 \(b_{pos}\) 尽可能小,在此基础上,考虑到后面的一些满足 \(a_i=pos\) 的位置,我们还要令 \(a_{pos}\) 尽可能小,于是 \(pos\) 自然就取最靠前的全局最小值的位置了。
接下来考虑 \(a\) 中至少有 \(2\) 个 \(-1\) 的情况。
首先和前面一种 case 类似,若存在 \(i\) 使得 \(a_i>i\land a_{a_i}=-1\),则令 \(a_{a_i}\gets 1\)。
然后考虑所有 \(a_i=-1\) 的位置,不妨找出 \(a\) 中第一个 \(1\) 的位置 \(p\),\(\forall a_i=-1,a_i\gets p\)。若不存在 \(a_i=1\),则令 \(p\) 为最后一个 \(a_i=-1\) 的位置,强制令 \(a_p\gets 1\)。这样子除了最后一个位置,每个 \(-1\) 对应的 \(b\) 都能取到 \(1\),比较优秀。
但是可以发现,这样没有考虑到那些 \(a_i\neq -1\land a_i<i\land a_{a_i}=-1\) 的 \(i\) 对应的 \(b_i\) 的取值,换句话说,我们还要尽可能最小化 \(a_i\)。怎样可以进一步最小化 \(a_i\) 呢?可以发现,我们只能考虑提前把某个 \(-1\) 的位置置为 \(1\)。考虑最小的 \(i\) 使得 \(a_i\neq -1\land a_i<i\land a_{a_i}=-1\),那么显然 \(i\) 之前的 \(-1\) 不能动,于是考虑 \(i\) 之后第一个 \(j\) 满足 \(a_j=-1\),我们可以尝试把这个 \(a_j\) 置为 \(1\)。具体来说,我们直接令前文中找到的 \(p\) 和这个 \(j\) 取 \(\min\) 即可。
依照上述讨论实现即可。时间复杂度为 \(\mathcal{O}(\sum n)\)。
代码
#include <bits/stdc++.h>using namespace std;#define lowbit(x) ((x) & -(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const int N = 5e5 + 5;template<typename T> inline void chk_min(T &x, T y) { x = min(x, y); }
template<typename T> inline void chk_max(T &x, T y) { x = max(x, y); }int T, n, cnt, a[N];int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> T;while (T--) {cin >> n, cnt = 0;for (int i = 1; i <= n; ++i) cin >> a[i], cnt += a[i] == -1;if (cnt == 1) {int pos = 0, mnp = 0; bool flag = 0;for (int i = n; i; --i) {if (a[i] == -1) pos = i;else {if (a[i] == pos) { flag = 1; break; }if (!mnp || a[i] <= a[mnp]) mnp = i;}}if (!mnp) mnp = pos;if (pos < a[mnp] || (pos == a[mnp] && pos < mnp)) mnp = pos;a[pos] = flag ? 1 : mnp;} else if (a[1] == -1 || a[1] == 1) {for (int i = 1; i <= n; ++i) if (a[i] == -1) a[i] = 1;} else if (cnt) {for (int i = 1; i <= n; ++i) if (a[i] > i && a[a[i]] == -1) a[a[i]] = 1;int pos = 1;for (int i = 1; i <= n; ++i)if (a[i] == 1) { pos = i; break; }else if (a[i] == -1) pos = i;for (int i = 1; i <= n; ++i) if (~a[i] && a[i] < i && a[a[i]] == -1) {int p = i + 1;while (p <= n && ~a[p]) ++p;chk_min(pos, p); break;}for (int i = 1; i <= n; ++i) if (a[i] == -1) a[i] = pos;a[pos] = 1;}for (int i = 1; i <= n; ++i) cout << a[a[i]] << " \n"[i == n];}return 0;
}