https://jzoj.net/senior/#main/show/6023
首先注意到这个最大值一定是由一个最高位为 1 1 1的数异或一个最高位不为 1 1 1的数异或得来。所以按照这个最高位是否为 1 1 1分为两个集合 S 0 , S 1 S0,S1 S0,S1.
之后我们可以用一个 T r i e Trie Trie简单的求出答案。但关键是怎么求排列。
事实上,我们可以贪心的选择这个字典序最小的。然后我们把这两个集合之间可以连的边都连上。仔细思考后发现,如果某个集合 A A A的某个点 a a a连向另一个集合的边数小于当前 A A A连向 B B B还剩余的边数,那么我们就一定可以选 a a a,或者这个集合只有一个数时,我们也可以选 a a a。当然,如果可以的话,我们可以跳到集合 B B B去选。这里就预处理一些东西,用一个set维护即可。
我打的很丑:
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a, b) memset(a, b, sizeof a)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define F(i, a, b) for (int i = (a); i <= (b); i ++)
const int N = 3e5 + 10, M = 40;
using namespace std;
int n, Ans, Mx, x, y, W, Sum[2], pt, tot, s0, s1, d0, cnt, st[N], S[N], Res[N], Ret[N], L[N], R[N];
int a[N], B[N], ANS[N], A[N], d[M], Son[2][M*N][2], ToT[2][M*N], Pre[2][M*N];
struct node {
int x, num;
bool operator < (const node a) const { return num < a.num; }
} T, t, b[N], S0[N], S1[N];
vector <int> V[N]; bool vis[N];
multiset <node> ST[2];
void Re(int &x) {
char c = getchar(); x = 0; int t = 1;
for (; !isdigit(c); c = getchar());
for (; isdigit(c); x = (x << 3) + (x << 1) + c - '0', c = getchar()); x *= t;
}
void Init() {
Re(n);
F(i, 1, n) Re(a[i]);
}
void Doit() {
do {
if (Mx) F(i, 1, n) a[i] = a[i] - (1 << (Mx - 1));
Mx = tot = 0;
F(i, 1, n) Mx = max(Mx, a[i]);
if (Mx == 0) {
F(i, 1, n)
printf("%d ", i);
exit(0);
}
Mx = floor(log(Mx) / log(2)) + 1;
F(i, 1, n) tot += floor(log(a[i]) / log(2)) + 1 == Mx;
} while (tot == n);
}
void GetAns() {
F(i, 1, n) b[i] = {i, a[i]};
sort(b + 1, b + n + 1); b[0].num = b[1].num - 1; int cnt = 0;
F(i, 1, n)
cnt += (b[i].num != b[i - 1].num), B[b[i].x] = cnt;
F(i, 1, n) {
d0 = 0, mem(d, 0);
for (int x = a[i]; x; d[++ d0] = x & 1, x >>= 1);
if (d0 == Mx) {
S1[++ s1] = {a[i], i}; int Rt = 0;
for (int j = Mx; j; ToT[0][Rt = Son[0][Rt][d[j --]]] ++)
if (!Son[0][Rt][d[j]])
Son[0][Rt][d[j]] = ++ cnt;
Pre[0][Rt] = B[i];
}
else {
S0[++ s0] = {a[i], i}; int Rt = 0;
for (int j = Mx; j; ToT[1][Rt = Son[1][Rt][d[j --]]] ++)
if (!Son[1][Rt][d[j]])
Son[1][Rt][d[j]] = ++ cnt;
Pre[1][Rt] = B[i];
}
}
Ans = 2e9;
F(i, 1, s0) { d0 = 0, mem(d, 0);
for (int x = S0[i].x; x; d[++ d0] = x & 1, x >>= 1);
for (int j = Mx, Rt = 0; j ; j --)
if (Son[0][Rt][d[j]])
Rt = Son[0][Rt][d[j]];
else
Rt = Son[0][Rt][1 - d[j]], S[i] = S[i] + (1 << (j - 1));
Ans = min(Ans, S[i]);
}
}
void GetSet_And_SomeInit() {
for (int x = Ans; x; A[++ A[0]] = x & 1, x >>= 1);
F(i, 1, s0) { d0 = 0, mem(d, 0);
for (int x = S0[i].x; x; d[++ d0] = x & 1, x >>= 1); int Rt = 0;
for (int j = Mx; j && Rt || j == Mx; Rt = Son[0][Rt][A[j] ^ d[j --]]);
Sum[0] += ToT[0][Rt];
Res[B[S0[i].num]] = ToT[0][Rt];
Ret[B[S0[i].num]] = Pre[0][Rt];
ST[0].insert({Pre[0][Rt], S0[i].num});
}
F(i, 1, s1) { d0 = 0, mem(d, 0);
for (int x = S1[i].x; x; d[++ d0] = x & 1, x >>= 1); int Rt = 0;
for (int j = Mx; j && Rt || j == Mx; Rt = Son[1][Rt][A[j] ^ d[j --]]);
Sum[1] += ToT[1][Rt];
Res[B[S1[i].num]] = ToT[1][Rt];
Ret[B[S1[i].num]] = Pre[1][Rt];
ST[1].insert({Pre[1][Rt], S1[i].num});
}
F(i, 1, n)
V[B[i]].push_back(i);
}
void Solve() {
t = *ST[0].begin();
if (Res[B[t.num]] == Sum[0] && ST[0].size() > 1 && ST[1].size())
t = *++ST[0].begin();
x = t.num, pt = t.x, T = t;
t = *ST[1].begin();
if (Res[B[t.num]] == Sum[1] && ST[1].size() > 1 && ST[0].size())
t = *++ST[1].begin();
y = t.num;
if (y < x)
x = y, pt = t.x, W = 1, T = t;
ST[W].erase(ST[W].find(T));
printf("%d ", x);
F(i, 2, n) {
vis[x] = 1;
Sum[W] -= Res[B[T.num]];
Sum[1-W] -= Res[B[T.num]];
Res[Ret[B[x]]] --;
t = *ST[W].begin();
if (Res[B[t.num]] == Sum[W] && ST[W].size() > 1 && ST[1-W].size())
t = *++ST[W].begin();
T = t, x = t.num == 0 ? 1e9 : t.num;
while (st[pt] < V[pt].size() && vis[V[pt][st[pt]]])
st[pt]++;
if (st[pt] < V[pt].size()) {
y = V[pt][st[pt]];
if (!(Res[B[y]] == Sum[1 - W] && ST[1 - W].size() > 1 && ST[W].size())) {
t = *ST[1-W].lower_bound({0, y}), y = t.num == 0 ? 1e9 : t.num;
if (y < x)
x = y, W = 1 - W, T = t;
}
}
pt = T.x;
ST[W].erase(ST[W].find(T));
printf("%d ", x);
}
}
int main() {
freopen("roast.in", "r", stdin);
freopen("roast.out", "w", stdout);
Init();
Doit();
GetAns();
GetSet_And_SomeInit();
Solve();
}