题目链接:点击查看

题目大意:给出一张有 n 个点和 m 条边的图,每个点都有一个种类,共有 k 个种类,现在要从 k 个种类中每次选出两种,对所有 C( k , 2 ) 种组合单独讨论,对于选出的两个种类中,包含的所有的点以及其连边所组成的子图,如果该子图可以拆分成二分图,那么答案加一

题目分析:参考博客:https://blog.csdn.net/Zenith_Habitant/article/details/109451857

k 的范围很大,正难则反,考虑计算不合法的组合个数,然后由总的合法个数减去就是答案了

首先看到题目中的二分图,不难想到其定义为:“不含有奇环的一个图”,而判断二分图的两种方法,一种是直接 dfs 染色,另一种方法就是对每个点建立虚点然后并查集维护,可以参考:CH - 4901 关押罪犯

因为总的边数只有 m 条边,换句话说,假设每条边 ( x , y ) 连接的 x 和 y 都属于不同的种类,最终也只有 m 种组合方案,所以非法的种类数最多只有 m 种

所以对于每条边 ( x , y ) 分类讨论,设 type[ x ] 是 x 的种类:

  1. 如果 type[ x ] == type[ y ],直接用并查集将其合并即可
  2. 如果 type[ x ] != type[ y ],将其加入所有,连接( type[ x ] , type[ y ] ) 这两个种类的边的集合中去

然后对于每个种类自己单独的连通块内,如果出现了奇环,说明当前这个种类无论和哪个组合匹配,都不可能产生贡献了,对于这些种类单独拿出来即可

然后就是对合并任意两个种类的那些边分组,依次合并,看看这两个种类组合的话是否会产生贡献,这里需要注意的是,因为对于合并每两个组的边集都是相互独立的,所以在进行完一次 “ 合并 ”,检查出答案后,需要及时撤销,这样就可以保证算法的正确性了,关于撤销可以直接用并查集的撤销来实现

代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;map<pair<int,int>,vector<pair<int,int>>>mp;//map[{type_a,type_b}]={(u1,v1),(u2,v2)...(uk,vk)}//表示连接两个组的边 struct revo
{int fax,fay;int rkx,rky;
};int a[N],b[N],f[N],rk[N],type[N],tot;bool fail[N];stack<revo>st;int find(int x)
{return f[x]==x?x:find(f[x]);
}void merge(int x,int y)
{int xx=find(x),yy=find(y);revo temp;temp.fax=xx,temp.fay=yy;temp.rkx=rk[xx],temp.rky=rk[yy];st.push(temp);if(rk[xx]>rk[yy])swap(xx,yy);f[xx]=yy;rk[yy]=max(rk[yy],rk[xx]+1);
}void revocation(int k)
{while(k--){revo node=st.top();st.pop();f[node.fax]=node.fax;f[node.fay]=node.fay;rk[node.fax]=node.rkx;rk[node.fay]=node.rky;}
}void init()
{for(int i=1;i<N;i++){f[i]=i;rk[i]=1;}
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);init();int n,m,k;LL ans=0;scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=n;i++)scanf("%d",type+i);for(int i=1;i<=m;i++)scanf("%d%d",a+i,b+i);for(int i=1;i<=m;i++)//同一种类的边,直接维护即可 {if(type[a[i]]==type[b[i]]){int xx=find(a[i]),yy=find(b[i]);if(xx!=yy)merge(a[i],b[i]+n),merge(b[i],a[i]+n);elsefail[type[a[i]]]=true;}}for(int i=1;i<=m;i++)//连接两个不同种类的边,将其归类 {if(type[a[i]]==type[b[i]])continue;if(fail[type[a[i]]]||fail[type[b[i]]])continue;if(type[a[i]]>type[b[i]])swap(a[i],b[i]);mp[make_pair(type[a[i]],type[b[i]])].emplace_back(a[i],b[i]);}for(auto node:mp)//node.second=vector<pair<int,int>>{int cnt=0;for(auto it:node.second)//it=pair<int,int>=(u,v){int x,y;tie(x,y)=it;int xx=find(x),yy=find(y);if(xx!=yy)merge(x,y+n),merge(y,x+n),cnt+=2;else{ans--;break;}}revocation(cnt);}LL cnt=0;for(int i=1;i<=k;i++)if(!fail[i])cnt++;ans+=cnt*(cnt-1)/2;printf("%lld\n",ans);return 0;
}

CodeForces - 1445E Team-Building(可撤销并查集)相关推荐

  1. codeforces 892E(离散化+可撤销并查集)

    题意 给出一个n个点m条边的无向联通图(n,m<=5e5),有q(q<=5e5)个询问 每个询问询问一个边集{Ei},回答这些边能否在同一个最小生成树中 分析 要知道一个性质,就是权值不同 ...

  2. 线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)

    题目链接 题目大意: 你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y ...

  3. 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解

    题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...

  4. 洛谷P7518:宝石(倍增、可撤销并查集)

    解析 算法一 定义 upx,kup_{x,k}upx,k​ 为节点 xxx 从自己的颜色所在位置在返祖链上往后跳 2k2^k2k 个颜色到达的节点. 可以像倍增一样的求解. 这样对于一次询问 (s,t ...

  5. CF603E-Pastoral Oddities【CDQ分治,可撤销并查集】

    正题 题目链接:https://www.luogu.com.cn/problem/CF603E 题目大意 开始时有nnn个点,没有边. 依次加入mmm条带权的边,每次加入后询问是否存在一个边集,满足每 ...

  6. BZOJ4358: permu(带撤销并查集 不删除莫队)

    题意 题目链接 Sol 感觉自己已经老的爬不动了.. 想了一会儿,大概用个不删除莫队+带撤销并查集就能搞了吧,\(n \sqrt{n} logn\)应该卡的过去 不过不删除莫队咋写来着?....跑去学 ...

  7. 【BZOJ4025】二分图(可撤销并查集+线段树分治)

    题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...

  8. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  9. CodeForces - 892E Envy(可撤销并查集)

    题目链接:点击查看 题目大意:给出一张由 n 个点 m 条边组成的连通图,有 q 次询问,每次询问给出一个边集,需要判断这些边是否可以同时出现在最小生成树上 题目分析:需要用到的一个性质是,对于同一个 ...

最新文章

  1. java response 对象_82 Java基础 Response对象
  2. ISME:林科院袁志林等-冷杉优势真菌共生发育的基因家族趋同演化及平衡选择机制...
  3. python小游戏编程实例-Python实现的弹球小游戏示例
  4. 执行umount 的时候却提示:device is busy 的处理方法
  5. mysql中如何操作字符串_mysql 字符串操作
  6. 网易云信亮相WOT, 打造“IM+连麦互动直播”云服务
  7. 安卓入门系列-07常用UI控件(长文)
  8. C#中的运算符、数组、枚举、结构体
  9. 一個便宜的高负载网站架构
  10. Shadow Map 原理和改进 【转】
  11. 前端开发面试题收集 JS
  12. 文件比较 增量 更新 系统发布 增量更新
  13. 原生 js 生成二维码
  14. 筹备酒吧之路——音响篇
  15. 王阳明:志不立,天下无可成之事
  16. 333教育综合推荐书籍
  17. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- Demo分析
  18. 7行代码制作一个超声波测距仪
  19. 作为程序员,我想养成的几个爱好
  20. 2021暑期学习第23天

热门文章

  1. MySQL高级 - SQL优化 - limit优化
  2. explain分析执行计划
  3. MyBatis 源码解读-获得Mapper 对象
  4. 高仿真的类-ApplicationContextAware
  5. CGLib 调用API 及原理分析
  6. serialVersionUIDtransient
  7. ThreadLocal的第二种用法 part1
  8. 分布式文件系统研究-测试-上传文件测试
  9. springboot整合filter
  10. 将微服务注册到Eureka Server上