ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

cf1559 D2. Mocha and Diana (Hard Version)

2021-09-02 22:01:41  阅读:216  来源: 互联网

标签:Diana 第二片 Hard Mocha int mp s2 第一片 森林


传送门

相较于D1的\(n^2\)暴力。这次肯定不行了。这时我们就要想如何快速合并2片森林中所有的树呢。

首先可以加完边后两片森林依旧为森林,因此最多可以加的边数为边数多的那片森林确定。这样我们不妨令边数多的森林为第一片森林,可以加的最多的边即把第一片森林搞得只剩下一棵树。

在第一片森林中两棵树合并时,两颗树需要分别提供一个连接点,并且这两个连接点在第二篇森林中不属于同一棵树。那么这两颗树可以通过这两个连接点来连接。

这个连接点是必然存在的,这里简略证明一下(口胡开始): 对于第一片森林中的两棵树,假设不存在这一连接点,那么即这两棵树上的点在第二片森林中属于同一棵树,此时有一条边的差异这是关键,后面口胡,那么在第一片森林中必然有额外的一点属于这两棵树中的一个,而又不属于第二片森林中的那棵树,假设不成立,因此必然存在这个连接点。(口胡结束)

之后我们该如何找这两个点呢?这是不妨逆向一下,我们来看在第一片森林的第\(i\)棵树如果要提供连接点位于第二片森林的第\(j\)棵树时,可以提供的点是谁,这里可以用二维map来储存。即\(mp[u][v]=i\)表示点\(i\)同时位于第一片森林的\(u\)树和第二片森林的\(v\)树,

这样,我们在合并第一片森林中的两棵树时,只要确定两棵树连接点分别属于第二片森林中哪棵树,只要保证不属于第二片森林中的同一棵树,就可以立即得到连接点(这里的连接点可以有多个,但我们只需要记住一个就行了),不用再枚举,这里我们只需要预处理出上面的\(mp\)数组,可以用\(stl\)的\(map\)储存。

然后合并时,将小的往大的合并,枚举小的,合并后同时更新第一片森林中新树的信息。同时我们看到在接上边后,第二片森林的连接情况也会有所变化,并且二者的联系\(mp[u][v]\)也会变化,因此我们需要同时存储第一片森林中的树能到的第二片树林中的哪些树 和 第二片森林能到第一片森林中的哪些树。

在合并时,假设第一片森林中两棵树为\(u,v\),其在第二片森林中的所属树分别为\(a,b\),这里保证\(a!=b\),然后合并时,将小的往大的合并,假设\(u\)树大于\(v\)树,则所有的\(v\)能到达的第二片森林的树的信息即\(mp\)数组合并到\(u\),即\(mp[u][s1(v)]=mp[v][s1(v)]\),同时删除\(s2(s1(v))中的点v并添加点u\),同理假设 \(a\)树大于\(b\)树,\(mp[s2(a)][a]=mp[s2(b)][b]\)删除在\(s1(s2(b))中的点b并加入a\)。

那么这里时间复杂度相当于\(x\)个数,每次选两两合并为一个数,代价为较小的那个数,当合并只剩下最后一个数时,最小的代价是多少,此时,当每次把最大的固定,把其他的往里面合并时,代价为线性复杂度.

但我们只能保证在第一片森林中是线性合并,在第二片森林中,我们只满足把小的向大的合并,这里的复杂度最坏是\(O(nlogn)\),满足最坏时的情况即类似线段树的情况,
此时合并的次数为\(\sum_{i=1}^{logn} \frac{n}{2^i}*2^{i-1}=\sum_{i=1}^{logn} \frac{n}{2}\)
是\(O(nlogn)\)级的,加上stl的\(O(logn)\)的复杂度,总算法复杂度\(O(n log^2n)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<cmath>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rpe(i,a,b) for(int i=a;i>=b;--i)
#define pts putchar('\n')
#define ptc putchar(' ')
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int inf=0x7f7f7f7f;
const ll linf=1e18;
const int maxn=1e5+9;
const int maxm=1e7+9;
const double PI=3.1415926;
const double eps=1e-5;
const ll mod=998244353;
const int base=131;
const int N=1e6;

namespace IO{
    ll read(){    
        ll a=1,b=0;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')a=-1;c=getchar();} 
        while(c>='0'&&c<='9'){b=(b<<3)+(b<<1)+c-'0';c=getchar();}
        return a*b ;
    }
    void print (ll x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) print(x/10);
        putchar(x%10+'0');
    } 
}
using namespace IO;

int n,m1,m2;
int fa1[maxn],fa2[maxn];
map<int,int>mp[maxn];
set<int>s1[maxn],s2[maxn];
vector<P>s,ans;
set<int>::iterator it1,it2,it;
int cnt[maxn];

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

void Merge(int x,int y){
    for(it=s1[y].begin();it!=s1[y].end();++it){
        mp[x][*it]=mp[y][*it];
        s1[x].insert(*it);
        s2[*it].insert(x);
        s2[*it].erase(y);
    }
}

void Merge_(int x,int y){
    for(it=s2[y].begin();it!=s2[y].end();++it){
        mp[*it][x]=mp[*it][y];
        s2[x].insert(*it);
        s1[*it].insert(x);
        s1[*it].erase(y);
    }
}
int main(){
    n=read(),m1=read(),m2=read();
    rep(i,1,n) fa1[i]=fa2[i]=i;
    int u,v;
    rep(i,1,m1){
        u=read(),v=read();
        fa1[find(fa1,u)]=find(fa1,v);
    }
    rep(i,1,m2){
        u=read(),v=read();
        fa2[find(fa2,u)]=find(fa2,v);
    }
    if(m1<m2) swap(fa1,fa2); 
    rep(i,1,n){
        u=find(fa1,i);v=find(fa2,i);
        mp[u][v]=i;
        cnt[u]++;
        s1[u].insert(v);
        s2[v].insert(u);
    }
    rep(i,1,n){
        if(find(fa1,i)==i) s.pb(P(-cnt[i],i));
    }
    sort(s.begin(),s.end());
    int len=s.size();
    u=s[0].second;
    rep(i,1,len-1){
        v=s[i].second;
        it1=s1[u].begin();
        it2=s1[v].begin();
        if( (*it1) == (*it2) ) it1++;
        ans.pb(P(mp[u][*it1],mp[v][*it2]));
        Merge(u,v);
        if(s2[*it1].size() < s2[*it2].size()) swap(it1,it2);
        Merge_(*it1,*it2);
        fa1[find(fa1,u)]=find(fa1,v);
    }
    print(ans.size());pts;
    for(auto x:ans){
        print(x.first);ptc;print(x.second);pts;
    }
    return 0;
} 

标签:Diana,第二片,Hard,Mocha,int,mp,s2,第一片,森林
来源: https://www.cnblogs.com/Mr-leng/p/15220975.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有