zoukankan      html  css  js  c++  java
  • 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;
        }
  • 相关阅读:
    epoll 使用详解
    STL 较详尽总结
    可视化对比排序算法
    统治世界的十大算法
    Vector Demo
    Git远程操作(附重要原理图)
    Wireshark(五):TCP窗口与拥塞处理
    Wireshark(四):网络性能排查之TCP重传与重复ACK
    Wireshark(三):应用Wireshark IO图形工具分析数据流
    Wireshark(二):应用Wireshark观察基本网络协议
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15156236.html
Copyright © 2011-2022 走看看