专栏文章

P10777 BZOJ3706 反色刷

P10777题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqf5emm
此快照首次捕获于
2025/12/04 03:47
3 个月前
此快照最后确认于
2025/12/04 03:47
3 个月前
查看原文
首先先进行存在性判定,由于要走奇数次黑边,偶数次白边,所以只有黑边会改变节点度数的奇偶性,所以不妨先只连黑边,如果出现度数为奇数的节点,那么一定无解。因为题目要求只能从一个点出发并且最终返回这个节点,那么遍历过程中每个点的进边和出边数量一定相同,也就一定不会改变其度数的奇偶性,所以度数为奇数的点最后度数一定无法变为零,一定无解。
然后考虑度数全为偶数的情况,显然可以发现连通块之间互不干扰,那么我们对每个连通块进行分析,我们可以把块中的白边当作两条边加入,加入后节点度数奇偶性不受影响,并且添加完边后块内一定联通,根据欧拉回路的性质,我们一定能做到从一个点开始不重复地走过这些边,并最终回到这个点。也就是说每个块对答案的贡献不超过 11,而显然只有在块内全是白点时贡献为 00,这个我们可以特判解决。
修改操作也很简单,直接修改这条边对应点的度数,相应地修改答案,单次操作复杂度可以控制在 O(1)O(1) 时间内完成。
初始化用并查集解决,总复杂度 O(nlog2n)O(n\log_{2}{n} )
代码很丑。
CPP
#include<bits/stdc++.h>
using namespace std;
template <typename T>
void in(T &x){
	char c=getchar(), f=1;
	while ((c<'0' || c>'9') && c!='-') c=getchar();
	if (c=='-') f=-1, c=getchar();
	for (x=0; c>='0' && c<='9'; c=getchar())
		x=x*10+c-'0';
	x*=f;
}
const int N=1e6+5;
struct node{
	int u,v,col;
}eg[N];
int n,m,fa[N],du[N],q,opt,x,ans,al,sz[N],f[N],g[N];
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	int x1=find(x),y1=find(y);
	if(x1==y1)return ;
	fa[x1]=y1;
	sz[y1]+=sz[x1];
}
int main(){
//	freopen("P10777.in","r",stdin);
//	freopen("P10777.out","w",stdout);
	in(n);in(m);
	for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;;
	for(int i=1;i<=m;i++){
		in(eg[i].u);in(eg[i].v);in(eg[i].col);
		if(eg[i].col==1){du[eg[i].u]++;du[eg[i].v]++;}
		merge(eg[i].u,eg[i].v);
	}
	for(int i=1;i<=n;i++){
		al+=du[i]&1;
		g[find(i)]+=du[i]==0;
	}
	for(int i=1;i<=n;i++){
		if(!f[find(i)]){
			f[find(i)]=1;
			ans++;
			if(g[find(i)]==sz[find(i)])ans--;
		}
	}
	in(q);
	while(q--){
		in(opt);
		if(opt==1){
			in(x);x++;
			if(eg[x].col==1){
				du[eg[x].u]--,du[eg[x].v]--;
				if(du[eg[x].u]==0){
					g[find(eg[x].u)]++;
				}
				if(du[eg[x].v]==0){
					g[find(eg[x].u)]++;
				}
				if(g[find(eg[x].u)]==sz[find(eg[x].u)])ans--;
			}
			else{
				du[eg[x].u]++,du[eg[x].v]++;
				if(du[eg[x].u]==1){
					if(g[find(eg[x].u)]==sz[find(eg[x].u)])ans++;
					g[find(eg[x].u)]--;

				}
				if(du[eg[x].v]==1){
					g[find(eg[x].u)]--;
				}
			}
			if(du[eg[x].u]&1)al++;
			else al--;
			if(du[eg[x].v]&1)al++;
			else al--;
			eg[x].col^=1;
		}
		if(opt==2){
			if(al)printf("-1\n");
			else printf("%d\n",ans);
		}
	}
	return 0;
}
/*
按连通块考虑
一次操作,因为一定有进有出,而且要求起点和终点相同,所以度数的奇偶性不变化
把黑边对度数的贡献记为1,白边贡献记为0
有度数为奇数的点直接输出无解

那么此时度数全为偶数,把白边当作两条相同的边加入,显然不影响度数的奇偶性,
而且由于这是一个连通块,当把所有白边都加入后,局部一定是联通图
根据欧拉回路的性质,一定可以以任意一个块内点为起点,不重复地走完这些边
因此把一个联通块全刷成白色至多需要一次操作
还可以发现,只有在该连通块内的边全为白色时,不需要进行操作,这个可以特判

那么我们只需要在进行每次操作1时,修改这条边所连两个点的度数信息,进而更新答案即可
*/

评论

1 条评论,欢迎与作者交流。

正在加载评论...