[CTS2024] 众生之门
跟众生之门一样难欸!
首先这题要求的东西很鬼,距离异或和,看起来毫无性质。
不过毫无性质也是有好处的,你发现你一共有 \((n-2)!\) 种排列方式,值却只在 \([0,n-1]\),也就是说取到一个值的概率会非常大!这种难以刻画的东西,显然是很难卡的,也就是说满足随机性。考虑到小数据随机方差可能会比较大,且 \(n\) 很小时会使得测试组数变大,我们对于 \(n\le 10\) 的情况跑暴力,否则我们跑 \(20n\) 次随机排列,我们并不需要对整个排列随机,直接随机交换两项即可。使用 \(\mathcal{O}(1)\) 求祖先的 trick 可以轻松通过。
对于输出答案我们可以记录每一时刻交换了哪些位置,然后记录在哪一时刻取到最小值就行了。
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= (r); ++ i)
#define rrp(i, l, r) for (int i (r); i >= (l); -- i)
#define eb emplace_back
using namespace std;
#define pii pair <int, int>
#define inf 1000000001
#define ls (p << 1)
#define rs (ls | 1)
#define fi first
#define se second
constexpr int N = 5e4 + 5, M = 2e5 + 5;
typedef long long ll;
typedef unsigned long long ull;
inline ll rd () {
ll x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar ();
}
return x * f;
}
int qpow (int x, int y, int p) {
int ret (1);
for (; y; y >>= 1, x = x * x % p) if (y & 1) ret = ret * x % p;
return ret;
}
int n, s, t;
int p[N];
int x[N * 20], y[N * 20];
vector <int> e[N];
int f[N][16], dep[N], dfn[N], dfu[N], tot;
mt19937 rnd (114514);
void dfs (int u, int fa) {
dfn[u] = ++ tot;
dep[u] = dep[fa] + 1;
for (auto v : e[u]) {
if (v == fa) continue;
dfs (v, u);
}
dfu[u] = tot;
}
int get (int x, int y) {
return dep[x] < dep[y] ? x : y;
}
int LCA_dep (int x, int y) {
if (dfn[x] >= dfn[y]) swap (x, y);
if (dfu[x] >= dfn[y]) return dep[x];
int k (__lg (dfn[y] - dfn[x] + 1));
return dep[get (f[dfn[x]][k], f[dfn[y] - (1 << k) + 1][k])] - 1;
}
int dist (int x, int y) {
if (! x || ! y) return 0;
return dep[x] + dep[y] - 2 * LCA_dep (x, y);
}
int q[N];
int calc (int x) {
return dist (p[x - 1], p[x]) ^ dist (p[x], p[x + 1]);
}
int C;
void solve () {
n = rd (), s = rd (), t = rd ();
rep (i, 1, n) e[i].clear ();
rep (i, 2, n) {
int u (rd ()), v (rd ());
e[u].eb (v), e[v].eb (u);
} tot = 0, dfs (1, 0);
rep (i, 1, n) f[dfn[i]][0] = i;
rep (j, 1, 15) {
rep (i, 1, n - (1 << j) + 1) {
f[i][j] = get (f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
}
int k = n * 20;
rep (i, 1, n) p[i] = i;
rep (i, 1, n) {
if (p[i] == t) swap (p[i], p[n]);
if (p[i] == s) swap (p[i], p[1]);
}
shuffle (p + 2, p + n, rnd);
rep (i, 1, n) q[i] = p[i];
int now (0), ans (n + 1), id (0);
if (n <= 10) {
sort (p + 2, p + n);
do {
now = 0;
rep (i, 1, n - 1) now ^= dist (p[i], p[i + 1]);
if (now < ans) memcpy (q, p, sizeof q), ans = now;
if (ans <= 1) break;
} while (next_permutation (p + 2, p + n));
} else {
rep (i, 1, n) now ^= dist (p[i], p[i + 1]);
rep (t, 1, k) {
int i (rnd () % (n - 2) + 2), j (rnd () % (n - 2) + 2);
while (j == i) j = rnd () % (n - 2) + 2;
x[t] = i, y[t] = j;
now ^= calc (i) ^ calc (j);
swap (p[i], p[j]);
now ^= calc (i) ^ calc (j);
if (now < ans) {
ans = now, id = t;
}
if (ans <= 1) break;
}
}
rep (t, 1, id) swap (q[x[t]], q[y[t]]);
now = 0;
rep (i, 1, n) printf ("%d ", q[i]), q[i] = p[i] = 0; puts ("");
}
int32_t main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
for (int T (rd ()); T; -- T) solve ();
}

浙公网安备 33010602011771号