CF1559 D2. Mocha and Diana (Hard Version)

这场区分度比较低完全就是手速场嘛...趁机上了波分。

感觉这场最有思维量的就是这道D2了(D1直接n2并查集水过去了)

从D1我们就有一种感觉,题目给我们的其实是两个森林,我们每次肯定是将森林中的两棵树连接在一起。

那么我们不妨设置1号节点所在的树为主树,让森林中其他树都尽可能连接到主树上去。

所以我们先按原图读进来,之后用并查集处理一开始的连接情况,并且父节点都尽量取小(因为1为主树)

之后我们尝试将其他不在主树上的点都连一条1 - i的边,使其与主树相连。如果能成功添加也要算做答案。

之后我们发现有些点是填加不了的,比如这个点在第一张图里已经在主树中,但是第二张图这个点不在主树中。

于是我们开两个数组记录这些点,如果在一不在二就放入v2, 在二不在一就放入v1。

为什么需要记录这些点呢?因为最后的答案必然是v1, v2的组合。

v1:在第一张图中不在主树上,但是在第二张图中在主树上

v2:在第二张图中不再主树上,但是在第一张图中在主树上

那么v1, v2进行连边就一定能让v1, v2在两张图都在主树上。

连上v1, v2后有些点就会不是可以选择的点了,于是我们需要将其弹出。之后重复这个过程即为答案。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e6 + 10;
     
    int n;
    int a[maxn];
    int fa[maxn];
     
    int _find(int x) {
        if (x == fa[x]) return x;
        return fa[x] = _find(fa[x]);
    }
     
    void _merge(int u, int v) {
        u = _find(u), v = _find(v);
        if (u == v) return ;
        if (u > v) swap(u, v);
        fa[v] = u;
    }
     
    int main() {
        int n, m1, m2;
        scanf("%d%d%d", &n, &m1, &m2);
        for (int i = 1; i <= 2*n; ++ i) {
            fa[i] = i;
        }
        for (int i = 1; i <= m1; ++ i) {
            int u, v; scanf("%d%d", &u, &v);
            u = _find(u), v = _find(v);
            _merge(u, v);
        }
        for (int i = 1; i <= m2; ++ i) {
            int u, v; scanf("%d%d", &u, &v);
            u += n, v += n;
            u = _find(u), v = _find(v);
            _merge(u, v);
        }
        stack<int> p1, p2;
        vector<pair<int, int> > rec;
        for (int i = 1; i <= 1; ++ i) {
            for (int j = i+1; j <= n; ++ j) {
                int u1 = _find(i), v1 = _find(j);
                int u2 = _find(i+n), v2 = _find(j+n);
                //cout << u1 << " " << v1 << " " << u2-n << " " << v2-n << endl;
                if (v1 != 1 && v2 != 1+n) {
                    _merge(1, v1);
                    _merge(1+n, v2);
                    rec.push_back({1, j});
                    continue;
                }
                if (v1 != 1) p1.push(j);
                if (v2 != 1+n) p2.push(j);
            }
        }
        while (p1.size() && p2.size()) {
            //cout << p1.top() << " " << p2.top() << endl;
            if (_find(p1.top()) == 1 && _find(p1.top()+n) == 1+n) {
                p1.pop();
                continue;
            }
            if (_find(p2.top()) == 1 && _find(p2.top()+n) == 1+n) {
                p2.pop();
                continue;
            }
            rec.push_back({p1.top(), p2.top()});
            _merge(p1.top(), p2.top());
            _merge(p1.top()+n, p2.top()+n);
            p1.pop();
            p2.pop();
        }
        cout << rec.size() << endl;
        for (auto i : rec) {
            cout << i.first << " " << i.second << endl;
        }
        return 0;
    }
原文地址:https://www.cnblogs.com/Vikyanite/p/15156236.html