Loading

[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 ();
}
posted @ 2025-09-30 15:14  lalaouye  阅读(9)  评论(0)    收藏  举报