把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ4874】筐子放球(特殊的一般图最大匹配)

点此看题面

大致题意:\(n\)个球和\(m\)个筐,每个球可以放入给定的两个筐中的一个。现让你把所有球都放入筐中,问最少有多少个筐有奇数个球。

大致思路

考虑对于能放入一个筐中的两个球,如果我们把它们一起放入,就不会改变筐中球数的奇偶性,不会影响答案。

用图论的方式来表示,就是在所有能放入同一个筐中的两个球之间连边,然后求出最大匹配,无法匹配的点就会对答案造成贡献。

这样似乎非常完美,然而,\(n\le2\times10^5\),显然不是带花树能跑得动的。。。

实际上,这张图是非常特殊的,每个连通块必然能够取到理论上的最大匹配,因此只要求出有多少个联通块大小为奇数即可。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
using namespace std;
int n,m,s[N+5],t[N+5],f[N+5];I int fa(CI x) {return f[x]?f[x]=fa(f[x]):x;}
I void Union(RI x,RI y) {(x=fa(x))^(y=fa(y))&&(f[x]=y);}//合并
int main()
{
	RI i,x;for(scanf("%d%d",&n,&m),i=1;i<=n;++i)
		scanf("%d",&x),s[x]?Union(i,s[x]),0:s[x]=i,//对于每个筐记下第一个球,其余球与它合并
		scanf("%d",&x),s[x]?Union(i,s[x]),0:s[x]=i;//同上
	for(i=1;i<=n;++i) ++t[fa(i)];//统计连通块大小
	RI ans=0;for(i=1;i<=n;++i) !f[i]&&t[i]&1&&++ans;//统计答案
	return printf("%d\n",ans),0;
}
posted @ 2020-06-11 14:52  TheLostWeak  阅读(161)  评论(0编辑  收藏  举报