Codeforces 1152E neko and flashback

题目链接:codeforces1152E

题意

有长为(n)的数组(a)和排列(p),构造以下数组:

  • 长为(n-1)的数组(b)(b_i = min{a_i, a_{i+1}})

  • 长为(n-1)的数组(c)(c_i = max{a_i, a_{i+1}})

  • 长为(n-1)的数组(b')(b_i' = b_{p_i})

  • 长为(n-1)的数组(c')(c_i' = c_{p_i})

现给定({b'})({c'}),输出一组可能的原数组(a),无解输出(-1)

数据范围:(n≤1e5)

题解

大概手膜一下就知道,原题相当于把每个(b_i)(c_i)之间连一条边求欧拉路径(或回路)

然而并不会这个东西去学习了一下。

Hierholzer算法可以在(O(V+E))的时间复杂度内求解欧拉路径。

首先判定是否有解并找好起点。

然后我们在图中随机游走。有时候我们会走进一个死胡同。

但是如果我们删掉已经走过的边,剩下的图是存在欧拉回路的,而且这张图的点集和已经走过部分的点集一定是有交的。

那么我们在走到这个交点时,先不走这条路径,而是把图剩下部分先求个欧拉回路后回到这个点,然后再走完剩下的路径。

具体实现时就是在图中随机游走,直到离开一个点的时候把这个点入栈,随后从栈底到栈顶输出即可。

但是需要注意两个细节。

一个是不要忘记判断图是否联通。

其次是在(dfs)时需要加上当前弧优化,不然会被(1-2, 1-2, 1-2, 1-2 ...) 这样的数据卡到(O(E^2))

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;

int n, m, E = 1, tot;
int a[N], b[N], num[N];
int fir[N], nex[N], arr[N], deg[N], ans[N], used[N];
stack<int> st;

void Add_Edge(int x, int y) {
    nex[++E] = fir[x];
    fir[x] = E; arr[E] = y;
}

void dfs(int x) {
    for (int &i = fir[x]; i; i = nex[i]) {
        if (used[i]) continue;
        used[i] = used[i ^ 1] = 1;
        dfs(arr[i]);
    }
    st.push(x);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; ++i) {
        scanf("%d", &a[i]);
        num[++tot] = a[i];
    }
    for (int i = 1; i < n; ++i) {
        scanf("%d", &b[i]);
        num[++tot] = b[i];
    }
    sort(num + 1, num + tot + 1);
    tot = unique(num + 1, num + tot + 1) - num - 1;
    for (int i = 1; i < n; ++i) {
        a[i] = lower_bound(num + 1, num + tot + 1, a[i]) - num;
        b[i] = lower_bound(num + 1, num + tot + 1, b[i]) - num;
        if (a[i] > b[i]) return 0 * puts("-1");
        Add_Edge(a[i], b[i]);
        Add_Edge(b[i], a[i]);
        ++deg[a[i]]; ++deg[b[i]];
    }
    int u = 0, v = 0;
    for (int i = 1; i <= tot; ++i) {
        if (deg[i] % 2 == 0) continue;
        if (!u) u = i;
        else if (!v) v = i;
        else return 0 * puts("-1");
    }
    if (!u) u = 1;
    dfs(u);
    int len = 0;
    if (st.size() != n) return 0 * puts("-1"); 
    while (!st.empty()) ans[++len] = st.top(), st.pop();
    for (int i = 1; i <= len; ++i) {
        printf("%d ", num[ans[i]]);
    }
    puts("");
    return 0;
}
原文地址:https://www.cnblogs.com/Vexoben/p/11728648.html