BZOJ #4874. 筐子放球

翻陈指导博客看到的题,顺手写掉没想到最近降智严重调了好久

首先我们考虑对于一对能放进同一个筐的球同时放入不会改变奇偶性

而因为刚开始所有筐的球都是偶数个(\(0\)个),因此我们需要尽可能的把多对的球匹配到一起

换句话说我们在所有能放进同一个筐的球之间连边,求出它们最大匹配后无法匹配的数就会对答案造成\(1\)的贡献

但是\(n\le 200000\)的数据范围显然是不能用带花树来搞的(幸好不用),我们仔细观察一下发现由于每个球只能放在两个筐子之一,因此每个联通块是一定可以匹配满的

因此现在我们只需要找出所有大小为奇数的联通块个数即可,直接并查集维护

#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int fa[N],size[N],s[N],n,m,x,y,ans;
inline int getfa(CI x)
{
	return x!=fa[x]?fa[x]=getfa(fa[x]):x;
}
int main()
{
	RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) fa[i]=i,size[i]=1;
	for (i=1;i<=n;++i)
	{
		scanf("%d%d",&x,&y);
		if (s[x]) getfa(i)!=getfa(s[x])&&(size[getfa(s[x])]+=size[getfa(i)]),fa[getfa(i)]=getfa(s[x]); s[x]=i;
		if (s[y]) getfa(i)!=getfa(s[y])&&(size[getfa(s[y])]+=size[getfa(i)]),fa[getfa(i)]=getfa(s[y]); s[y]=i;
	}
	for (i=1;i<=n;++i) if (getfa(i)==i&&(size[i]&1)) ++ans;
	return printf("%d",ans),0;
}
posted @ 2020-09-24 21:09  空気力学の詩  阅读(97)  评论(0编辑  收藏  举报