LGP10777 反色刷 学习笔记
LGP10777 反色刷 学习笔记
题意简述
给定一个 \(n\) 点 \(m\) 边的简单无向图。边有黑白两种颜色。需要支持两种操作共 \(q\) 次:
1 x:将第 \(x\) 条边反色。2求出以“回路反色操作”将图刷成全白的所需要的最少次数。字面意思地,“回路反色操作”就是从任意点出发,每经过一条边则将其反色,最后需回到起点。如果不存在可行方案,输出-1。
\(n,m,q\le 10^6\)。
做法解析
首先我们先来解决下有无解判定的问题。这题看着就和欧拉回路相关,所以往相关东西上面靠,比如考虑点的度数。事实也的确如此,有解当且仅当每个点连接的黑边数量为偶数,由欧拉回路知识证明显然。
然后我们再来考虑下答案上下界相关的问题。我们发现,一个极大的仅包含黑边的连通块显然是可以一笔画的;我们又发现,如果两个极大的仅包含黑边的连通块在原图里面可以连通,那我们可以把它们一起一笔画了(具体来说,就是我们先把黑连通块一画完,再走一段路到黑连通块二,把黑连通块二画完,再顺着刚才的路原路返回,这样两个黑连通块都被干掉,中间那段路走两次抵消了)。
所以得到结论:在有解的情况下,答案即为原图中存在黑边的连通块个数。
代码实现不需要我多讲了吧,详见代码。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e6+5;
int N,M,Q,X,Y,Z,deg[MaxN],Opt;
struct edge{int u,v,w;}E[MaxN];
struct UnionFind{
int n,ufa[MaxN];
void init(int x){n=x;for(int i=1;i<=n;i++)ufa[i]=i;}
int find(int u){return ufa[u]==u?u:ufa[u]=find(ufa[u]);}
void merge(int u,int v){ufa[find(v)]=find(u);}
}UniFd;
int csum,ans,bla[MaxN];
void addudge(int u,int v,int w,int i){
E[i]={u,v,w};UniFd.merge(u,v);
csum-=(deg[u]+deg[v]);deg[u]^=w,deg[v]^=w;csum+=(deg[u]+deg[v]);
}
int main(){
readis(N,M),UniFd.init(N);
for(int i=1;i<=M;i++)readis(X,Y,Z),addudge(X,Y,Z,i);
for(int i=1,fu;i<=M;i++)if(E[i].w)fu=UniFd.find(E[i].u),ans+=(!bla[fu]),bla[fu]++;
readi(Q);while(Q--){
readi(Opt);
if(Opt==1){
readi(X),X++;auto [u,v,w]=E[X];int fu=UniFd.find(u);
csum-=(deg[u]+deg[v]);deg[u]^=1,deg[v]^=1;csum+=(deg[u]+deg[v]);
if(E[X].w)E[X].w=0,bla[fu]--,ans-=(!bla[fu]);
else E[X].w=1,ans+=(!bla[fu]),bla[fu]++;
}
if(Opt==2)writil(csum?-1:ans);
}
return 0;
}
浙公网安备 33010602011771号