首页 > 其他分享 >CF22E 题解

CF22E 题解

时间:2024-07-25 16:44:11浏览次数:13  
标签:lf rt int 题解 CF22E 叶子 fa find

题面

注意到题目给的图为基环树森林。

因为一个(\(n>1\))的强连通图每个点都要有出度和入度,所以:

对于每个基环树,叶子结点是没有入度的,所以一定要有一条从环上出发的路径经过这个点。

对于基环树的环,注意到它缩点后没有出度,所以一定要有一条出边。

注意到叶子结点的需求和根节点相反,所以可以从根节点边到叶子结点,这样可以最大化配对的数量。

构造方法为:考虑从(缩点后的)树 \(T1\) 的根节点连向 \(T2\) 的叶子结点(如果没有叶子就连根),再从 \(T2\) 的根节点开始继续连边。

特别地:\(Tn\) 向 \(T1\) 连边。如果只有一棵树就是 \(T1\) 的根向自己叶子连边。

对于还没有入度的叶子,随便找个有入度的叶子,向这些没入度的叶子连边就可以了。

因为最大化了配对的数量,答案为有需求的点减去配对数量,所以答案一定最小。


缩点和找每一棵树的叶子可以用并查集解决,写起来更简单。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e5 + 5;
int deg[N], n, fa[N];

vector<int> lf[N];

int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) fa[i] = i;
    for(int i = 1; i <= n; i ++)
    {
        int x; cin >> x;
        fa[find(i)] = find(x);
        deg[x] ++;
    }
    vector<int> rt;
    for(int i = 1; i <= n; i ++)
    {
        if(!deg[i]) lf[find(i)].push_back(i);
        if(find(i) == i) rt.push_back(i);
    }
    vector<pair<int, int>> ans;
    int lst;
    for(int i = 0; i < rt.size(); i ++)
    {
        int u = rt[i], v = rt[(i + 1) % rt.size()];
        int x = rt[i], y;
        if(lf[v].empty()) y = v;
        else y = lf[v].back(), lf[v].pop_back();
        if(x != y) ans.push_back({x, y});
        lst = y;
    }
    for(int i : rt)
    for(int j : lf[i])
        ans.push_back({lst, j});
    cout << ans.size() << "\n";
    for(auto [x, y] : ans) cout << x << " " << y << "\n";

    return 0;
}

标签:lf,rt,int,题解,CF22E,叶子,fa,find
From: https://www.cnblogs.com/adam01/p/18323536

相关文章

  • 题解:AT_arc116_e [ARC116E] Spread of Information
    题目链接思路看到最大值最小首先可以想到二分,发现答案具有单调性,那么思考如何在\(O(n)\)的时间内判断是否合法。考虑贪心,在最远没覆盖的点的距离和要判断的\(mid\)刚好相等的时侯再选择一定不劣,因为这样覆盖的点最多,那么从叶子节点向上回溯,处理它的所有儿子,判断是否选择该......
  • LG3107 [USACO14OPEN] Odometer S 题解 (数位DP+容斥)
    题意定义一个数是神奇的当且仅当这个数中有一个数位出现了一半及以上,比如112,2233。求\([l,r]\)中有多少个好的数字,\(100\lel,r\le10^{18}\)。题解考虑数位DP,先把答案转为\(Ans(r)-Ans(l-1)\),我们钦定一个数\(k\)让他必须出现多于一半,然后我们想求\([1,x]\)中有多少......
  • CF1015F 题解
    题面考虑这样的匹配问题,可以想如何确定第一次匹配,这样可以不重不漏地计数。考虑dp的时候同时维护有几个括号没有匹配,匹配到\(s\)的第几位,所以令\(f(i,j,k)\)表示dp到(要计数的序列的)第\(i\)个字符,有\(j\)个左括号没有匹配,匹配到\(s\)的第\(k\)位。转移很容易,考......
  • 程序设计:C++入门教程(速成) + 15道经典例题(附带例题解析)
    本文章以实用为主,若实在是不明白文字所表达的内容,无脑复制代码,自己动手运行一下,实验一下即可理解文章内容,放心,代码是全的,全选复制粘贴即可不废话,直接开整数据类型常用数据类型int:整数类型,用于表示整数值。例如:1,2,-3,0等。float:单精度浮点数类型,用于表示带有小数点的数......
  • AT_arc116_e [ARC116E] Spread of Information 题解
    题目传送门前置知识二分答案|树形DP解法答案显然具有单调性,考虑二分答案。设当前二分出的答案为\(mid\),则等价于覆盖距离为\(mid\)的情况下进行选点。做法同luoguP3942将军令,考虑进行贪心,对于深度最深的叶节点将选择的点放在边界时,即取\(mid\)级祖先时,覆盖的范......
  • 题解—[ABC265E] Warp
    题面简单计数DP。由于数据范围很大,所以状态不能常规设置为\(dp_{i,j}\)。注意到\(n\)只有\(300\),考虑设\(dp_{i,j,k}\)表示三种行走方法分别使用\(i\),\(j\),\(k\)次的路径数量。状态转移很简单,先计算出来当前所在位置,如果是障碍就跳过,否则$dp_{i,j,k}=dp_{i-1,j,k}+dp......
  • P2671 [NOIP2015 普及组] 求和 题解
    题目:P2671NOIP2015普及组求和题意给定一个带有颜色和数字的序列,我们要寻找三元组\((x,y,z)\)满足以下条件:\(y\)为\(x\)和\(z\)的中点且都为整数。\(color[x]=color[z]\)。我们命这样一个三元组对答案的贡献为\((x+z)*(num[x]+num[z])\)。整个序列的总价值为每个......
  • Temperature 题解
    前言题目链接:洛谷;SPOJ;Hydro&bzoj。题意简述有一个长度为\(n\)的序列,每个位置值的范围为\([L_i,R_i]\)内,求原序列可能的最长不降子串长度。题目分析尝试找一些性质。发现,连续一段合法的区间,都能分成若干真正参与最长不降子串,以及紧跟着的若干包含\(L_i\)的位置。下图......
  • [ABC318E]Sandwiches 题解
    题意给定一个序列\(A\),要求找有多少个三元组\((i,j,k)\)满足以下条件:\(1\lei<j<k\leN\)\(A_i=A_k\)\(A_i\neA_j\)思路相当于是找每两个相同的元素中有多少个不同的数字。例如:12131答案显然是4,即是\((1,2,3)(1,2,5)(1,4,5)(3,4,5)\)。用\(q[A[i]]\)......
  • [题解]CF117C Cycle
    思路发现最简单的方法就是直接枚举三个点,但是复杂度\(\Theta(n^3)\)无法接受。考虑枚举一个点,并确定它的一条边,那么只需要再枚举一个点了。于是转化为了,对于每一个点找到其最好的出边。观察下图,\(a\toc\)的边是不必要的。因为,如果有一个三元环包含\(a\toc\),那么一定能......