[BalticOI 2016] 交换 (Day2) 题解
[BalticOI 2016] 交换 (Day2) 题解
使用xxy神秘做法,只有对上脑电波才看得懂。
首先把序列变成一棵树,那么我们先考虑这个问题的一个子问题,对于根节点 \(a\) 和两个儿子 \(b\) 和 \(c\),如果 \(a\) 最小就保持不变,否则如果 \(b\) 最小可以交换 \(a\) 和 \(b\) ,最麻烦的是 \(c\) 最小,因为可能存在儿子是 \(a\),\(b\)和 \(b\),\(a\) 两种情况,我们不好知道选择哪个情况,不妨先变为一个集合 \(\{a,b\}\),表示两种情况皆有可能发生,于是我们可以这样构建一个数据结构,将 \(a\) 和 \(b\) 像kruskal重构树一样连在一起,后面一直这么干,但是因为我们会往两边都下传递,导致不是一棵树,可能有这样的情况
o o
/ \ / \
o o o
/ \
a b
但是,我们可以将核心部分看为一个倒着的二叉树,每个核心点有向外挂着的点,中间的点表示每个原树上的节点,指向的集合表示可能取这些值。也就是说每条边都代表一次选择的机会,因为选了就不能再选了,然后于是我们取出一个点的最小值后,删除直接把路径上的边删完,因为树深是log的,不会死。然后其实这颗树可以直接对应到原树,我们直接在原树上维护,每个点维护 \(x,y,z\) 表示这个点备选值为 \(x\) 和 \(y\),以及 \(z\) 表示是否继承父亲的集合。
然后我们考虑如何构建这棵树,如果目前的集合为 \(S\),我们选取最小值,令其为 \(S_{mn}\),如果它最小,那么两个儿子 \(x(ls)=a[ls],y(ls)=\infty,z(ls)=0\) 右侧同理;如果 \(b\) 最小,那么我们将右儿子直接封死,左儿子继承父亲,然后对于 \(c\) 最小,我们将左右儿子都继承父亲,并且将父亲的 \(y\) 设为 \(b\),我们可以保证父亲y是空的,因为根据前面的设定,确实没有这种情况。
然后这就是代码,上文讲的极其抽象,只能意会。
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 5;
#define ls(i) (i << 1)
#define rs(i) (i << 1 | 1)
#define fa(i) ((i) >> 1)
int x[N], y[N]; bool z[N];
const int INF = 1e9;
pair<int, int> getmn(int id) {
int u = id;
int mn = 1e9, mid = -1;
while (u) {
if (min(x[u], y[u]) < mn) {
mn = min(x[u], y[u]);
mid = u;
}
if (z[u])
u = fa(u);
else
break;
}
return {mn, mid};
}
void del(int u, int v) {
while (u != v) {
z[u] = 0;
u = fa(u);
}
x[v] = max(x[v], y[v]);
y[v] = INF;
}
int val[N], ans[N];
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n * 2 + 1; i++) val[i] = INF;
for (int i = 1; i <= n; i++) {
cin >> val[i];
}
x[1] = val[1], y[1] = INF, z[1] = 0;
for (int i = 1; i <= n; i++) {
pair<int, int> mn = getmn(i);
if (mn.first < val[ls(i)] && mn.first < val[rs(i)]) {
ans[i] = mn.first;
del(i, mn.second);
if (ls(i) <= n) x[ls(i)] = val[ls(i)], y[ls(i)] = INF, z[ls(i)] = 0;
if (rs(i) <= n) x[rs(i)] = val[rs(i)], y[rs(i)] = INF, z[rs(i)] = 0;
}
else if (val[ls(i)] < mn.first && val[ls(i)] < val[rs(i)]) {
ans[i] = val[ls(i)];
if (ls(i) <= n) x[ls(i)] = INF, y[ls(i)] = INF, z[ls(i)] = 1;
if (rs(i) <= n) x[rs(i)] = val[rs(i)], y[rs(i)] = INF, z[rs(i)] = 0;
}
else {
ans[i] = val[rs(i)];
y[i] = val[ls(i)];
if (ls(i) <= n) x[ls(i)] = INF, y[ls(i)] = INF, z[ls(i)] = 1;
if (rs(i) <= n) x[rs(i)] = INF, y[rs(i)] = INF, z[rs(i)] = 1;
}
}
for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
cout << '\n';
}
int main() {
// freopen("swap.in", "r", stdin);
// freopen("swap.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号