首页 > 其他分享 >CF1559D2 Mocha and Diana (Hard Version) 题解

CF1559D2 Mocha and Diana (Hard Version) 题解

时间:2023-06-07 09:45:48浏览次数:52  
标签:连通 CF1559D2 fa Diana 题解 int vec getfa 加边

Luogu | Codeforces

题意

给定两个森林 \(A\) 和 \(B\),均有编号 \(1\) 到 \(n\) 的节点,边数分别为 \(m_1,m_2\)。

现在进行加边操作,但是有两个要求:

  • 如果在第一个森林加一条 \((u,v)\) 的边,第二个森林也要进行同样的操作。反之同理。
  • 加边后两个森林依旧是森林。一棵树也是森林。

求最多能加几条边,并输出加边方案。若有多解,输出任意一种。

\(1\le n\le10^5\)。\(0\le m_1,m_2<n\)。

思路

“加边后森林依旧是森林” 的意思是,若 \((u,v)\) 已经连通,则不能加边,否则就成环了。

首先有一个暴力的做法:用并查集维护连通性,枚举所有点对 \((u,v)\),如果 \((u,v)\) 在 \(A\) 和 \(B\) 中都不连通,则加边。

这样做为什么是对的呢?我们将连通块看成一个整体,那么连边就相当于在连通块之间加边。那么,每连一条边,两个图中都会少一个连通块。并且,可以证明两个森林到最后一定会至少有一个是树(证明见下)。因此一直这样连就可以了。

证明:假设现在已经不能连边。不妨设 \(A\) 存在两个或多个连通块,那么所有在 \(A\) 中不连通的点对 \((u,v)\),一定在 \(B\) 中连通。

因此,对于 \(A\) 中的一个连通块 \(C\),对于所有 \(u\in C,v\notin C\),有 \((u,v)\) 在 \(B\) 中连通。 由此也可知 \(C\) 中的点在 \(B\) 中两两连通,不在 \(C\) 中的点在 \(B\) 中两两连通。所以所有点在 \(B\) 中两两连通,即 \(B\) 是一棵树。

平均时间复杂度 \(O(n^2\alpha(n))\),无法通过。

考虑如何优化这个贪心。

我们确定一个中心点 \(s=1\)。

考虑一个点 \(x\) 有多少种状态:

  1. \(x\) 与 \(s\) 在 \(A\) 中连通,在 \(B\) 中连通;
  2. \(x\) 与 \(s\) 在 \(A\) 中连通,在 \(B\) 中不连通;
  3. \(x\) 与 \(s\) 在 \(A\) 中不连通,在 \(B\) 中连通;
  4. \(x\) 与 \(s\) 在 \(A\) 中不连通,在 \(B\) 中不连通。

首先,枚举所有 \(x\),如果 \(x\) 为状态 4,则 \(x\) 与 \(s\) 间连一条边。

然后我们考虑还有哪些点之间能连边。状态 1 肯定不能连边,考虑状态 2 和 3。

我们仍然把连通块看成整体。如下图:(方点代表连通块,数字代表状态)(当然实际情况很可能不是这样)

我们发现可以这样连边:

因此,记录所有状态为 2 和 3 的连通块(具体实现见代码),然后尽量一对一连边。

最坏时间复杂度 \(O(n\log n)\),可以通过。

代码

#include <vector>
#include <iostream>
#define f(x, y, z) for (int x = (y); x <= (z); ++x)
using namespace std;
typedef pair<int, int> pii;
int constexpr N = 1e5 + 10;
int n, m[2], u, v;

int fa[2][N];
int getfa(int x, int f) { return x == fa[f][x] ? x : fa[f][x] = getfa(fa[f][x], f); }
void unionn(int x, int y,int f) { fa[f][getfa(x, f)] = getfa(y, f); }

vector<pii> ans;
vector<int> vec[2];

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    cin >> n >> m[0] >> m[1];
    f(i, 1, n) fa[0][i] = fa[1][i] = i;
    f(j, 0, 1) f(i, 1, m[j]) {
        cin >> u >> v;
        if (getfa(u, j) ^ getfa(v, j)) unionn(u, v, j);
    }
    f(i, 2, n) if ((getfa(1, 0) ^ getfa(i, 0)) && (getfa(1, 1) ^ getfa(i, 1))) //状态 4
        ans.emplace_back(1, i), unionn(1, i, 0), unionn(1, i, 1);
    f(i, 2, n) f(j, 0, 1) if (getfa(1, j) ^ getfa(i, j)) //状态 2 和 3
        vec[j].push_back(i), unionn(1, i, j); //记录的同时 unionn, 则这个连通块其他点不会再被记录
    if (vec[0].size() > vec[1].size()) swap(vec[0], vec[1]);
    cout << ans.size() + vec[0].size() << '\n';
    for (auto [u, v]: ans) cout << u << ' ' << v << '\n'; //c++17
    for (int i = 0; i < (int)vec[0].size(); ++i)
        cout << vec[0][i] << ' ' << vec[1][i] << '\n';
    
    return 0;
}

标签:连通,CF1559D2,fa,Diana,题解,int,vec,getfa,加边
From: https://www.cnblogs.com/f2021ljh/p/17462479.html

相关文章

  • 应用问题解决-分布式锁(LUA保证删除原子性)
    问题:删除操作缺乏原子性场景1、index1获得锁、执行具体操作、比较lock的uuid值确实和自己生成的uuid是否相等,相等则删除锁。uuid=v1set(lock,uuid)uuid.equals(get("lock"))2、但是index1执行删除前,lock刚好过期时间已经到了,被redis自动释放3、此时index2获取锁,执行具体......
  • 在centos7升级nodejs存在的无法切换版本的问题解决
    1.安装n管理工具npminstall-gn安装最新版本nlatest安装指定版本 n8.11.3 2.切换nodejs版本n选择已安装的版本 ο node/8.11.3  node/10.4.1查看当前版本node-v,下面表示已切换成功v8.13.3但问题来了,切换后,查看版本还是原来的v6.13.3,看下面 使用n切换nodejs......
  • 应用问题解决——缓存穿透、缓存击穿、缓存雪崩
    一、缓存穿透缓存穿透:key对应的数据在数据源并不存在,每次针对key的请求从缓存中获取不到,请求都会压到数据源,从而可能压垮数据源,比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库现象:1、应用服务器压力变大2、redis命中率......
  • Meteors 题解
    Meteors蒟蒻初学整体二分,写一篇题解记录一下思考与看法。题目大意在一个环形的轨道上分别着若干国家的空间站,在接下来的一段时间内会出现若干次陨石,每次出现在环形的某一段轨道,每个国家都想收集一定量的陨石,需要判断每个国家最少在什么时候可以集齐所需的陨石。思路分析首先......
  • Full Tank 题解
    FullTank题目大意给定一张\(n\)个点,\(m\)条边的连通无向图,在每个点有一个加油站,油价为该点的点权,每条边的油耗为该边的边权。现给出若干询问,问一辆油箱容量为\(c\)的车子是否能从\(s\)开到\(e\),如果可以,求出最小所需的钱。思路分析看到这种有图有权求最小消耗的题,我......
  • Visible Lattice Points 题解
    VisibleLatticePoints题目大意给定一个\(N×N×N\)的由若干点组成的立方体,点的坐标从\((0,0,0)\)到\((N,N,N)\),求从点\((0,0,0)\)处可以看见多少个点。思路分析我们将立方体上的点分成三类:在\(xy,yz,xz\)平面上的点。在\(x,y,z\)轴上的点。即不在平面,也不在......
  • Substring of Sorted String 题解
    SubstringofSortedString写篇题解纪念一下蒟蒻第一次赛时切出的F题。题目简述对一个字符串进行单点修改,区间判断操作。修改操作为将一个字符修改为另一个,判断操作为判断区间是否是整个字符串升序排序后的字串。思路分析蒟蒻第一眼线段树,但刚开始没仔细看题,以为是判断区......
  • DRTREE - Dynamically-Rooted Tree 题解
    DRTREE-Dynamically-RootedTree本题建议评蓝。思路:题目就是要对一颗不定根树求子树权值和。这题不带修,如果带修难度会增加一点,就跟遥远的国度差不多。首先分析一下在以不同根下子树的变化。当一颗树以1号节点为根时,比如说长这样:假设每个点的权值为1,那么这8个点......
  • 逛森林 题解
    P5344逛森林题目大意原题的题目大意已经很明确了要这个干嘛给定一些孤立点,将要进行两种操作:若两点之间不可以通过\(1\)类边连通,则在两点之间连双向\(1\)类边若\(u_1,v_1\)和\(u_2,v_2\)均可以通过\(1\)类边连通,则从\(u_1\tov_1\)的唯一路径上的所有点均向......
  • OTOCI 题解
    OTOCI题目大意给定\(n\)个带权的点,需要进行四种操作:查询两点连通性;加边;修改点权;查询两点路径的权值和。思路分析首先观察题目,我们会发现,在所有的操作结束后,所有的点构成一个森林,这是因为题目中的加边是建立在两点不连通的基础上的,所以不会形成任何的环,到最后自然形成了一个......