[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; 
}
posted @ 2026-10-29 20:34  MikotoHohenz  阅读(3)  评论(0)    收藏  举报