zoukankan      html  css  js  c++  java
  • CF1559D Mocha and Diana 题解

    Codeforces
    Luogu

    Description.

    给定两棵森林,节点编号都是 \([1,n]\)
    每次操作选出两个节点 \(x\)\(y\),满足在两棵树上 \(x\) 号节点均不和 \(y\) 号联通,并把他们相连。
    最大化操作次数,并构造。

    Solution.

    设第一片森林的连通块个数为 \(tot_1\),第二片为 \(tot_2\)
    那我们答案上界是 \(n-\max(tot_1,tot_2)\)
    我们发现下界也是,尝试证明。
    考虑最终状态,考虑连通块数量多的一片森林,设这片为 \(A\),另一片为 \(B\)
    我们发现如果 \(A\) 中存在 \(x\)\(y\) 不联通,而 \(B\) 中它们也不联通,那就可以对 \(x\)\(y\) 操作。
    所以我们说明了如果 \(A\) 中的不同连通块内两个数,他们在 \(B\) 中一定联通。
    所以如果 \(A\) 中连通块数 \(\ge 2\),那我们发现 \(A\) 中两两联通。
    如果 \(A\) 中连通块数 \(=1\),说明 \(B\) 中连通块数 \(\le 1\),也两两联通。
    所以 D1 直接暴力枚举两个点即可。


    没找到性质
    然后考虑不暴力。
    钦定一个观察点 \(x\),先找到所有可以和它连边的点,连掉。
    如果两边都联通,那对面点没什么花样。
    如果一边联通一边不联通,那找到所有这样的两组点(按哪边联通分类)。
    然后尽量匹配即可。
    因为 \(a\)\(x\) 联通,\(x\)\(b\) 不联通可以推出 \(a\)\(b\) 不联通。

    Coding.

    点击查看颓疯代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),bz=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) bz=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	bz?x=-x:x;
    }/*}}}*/
    int n,m1,m2,a[100005],ta,b[100005],tb;vector<pair<int,int> >rs;
    struct dsu
    {
    	int fa[100005];
    	inline void init(int n) {for(int i=1;i<=n;i++) fa[i]=i;}
    	inline int getf(int x) {return fa[x]==x?x:fa[x]=getf(fa[x]);}
    	inline void mrg(int x,int y) {x=getf(x),y=getf(y);if(x^y) fa[x]=y;}
    	inline char chk(int x,int y) {return getf(x)!=getf(y);}
    }A,B;
    inline void ad(int x,int y) {rs.push_back(make_pair(x,y));}
    inline void flush()
    {
    	printf("%d\n",(int)rs.size());
    	for(auto x:rs) printf("%d %d\n",x.first,x.second);
    }
    int main()
    {
    	read(n),read(m1),read(m2),A.init(n),B.init(n);
    	for(int i=1,x,y;i<=m1;i++) read(x),read(y),A.mrg(x,y);
    	for(int i=1,x,y;i<=m2;i++) read(x),read(y),B.mrg(x,y);
    	for(int i=2;i<=n;i++) if(A.chk(1,i)&&B.chk(1,i)) A.mrg(1,i),B.mrg(1,i),ad(1,i);
    	for(int i=2;i<=n;i++) if(A.chk(1,i)) a[++ta]=i,A.mrg(1,i);
    	for(int i=2;i<=n;i++) if(B.chk(1,i)) b[++tb]=i,B.mrg(1,i);
    	for(int i=1;i<=ta&&i<=tb;i++) ad(a[i],b[i]);
    	return flush(),0;
    }
    
  • 相关阅读:
    C#产生不重复随机数
    NT6 HDD Installer(硬盘装系统工具)装系统
    R语言实现 广义加性模型 Generalized Additive Models(GAM) 入门
    matlab小段代码学习
    java连接sql server2005
    python正则表达式
    Ubuntu下安装配置JDK 7
    mysql取代rand()的高效率随机读取方法
    UVA 1335 Beijing Guards
    杂思
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15168055.html
Copyright © 2011-2022 走看看