电压
简化题意
给定若干无向图,点值 \(\in \left\{0,1\right\}\), 对于每条边,若边的两端点权不同,边被标记为可行,否则为不可行,对于每条边,判断是否存在一种给点赋值的方法,使得图中只有该边不可行,而其他边均可行,最后输出这种边的数量。
做法
先明确思路,这里的可行问题显然是与奇偶性有关的。
- 性质一:
如果我们现在有个奇环,无论怎么标都必然有条边不可行。 - 性质二:
反之为偶环的话,必然可以找到一种所有边均可行的方案。同时,如果该环中存在不可行的边,这种边的边数必定为偶数。 - 性质三:
同时又因为我们只能有一条边不可行,所以可以发现,这条边必须出现在所有奇环中,并且不出现在任何偶环中 (否则由性质二可以得到必然存在两条及以上不可行的边)。
有了这三个性质这个问题就简单了,我们的任务就是求出有多少边出现在所有奇环中,并且不出现在任何偶环中,通过树上差分统计一下即可。
关于树上差分在稍微补充一点,通过 dfs 序操作后,我们可以把图上的边分为树边和返祖边,而形成环的方式,就是若干条树边加上一条返祖边,所以这里我们对每条返祖边进行操作,对当前 \(u\) 加 1, 对返祖边通向的 \(v\) 减 1 即可。
注意点就是由于我们是边的差分,所以最后判断一下这个点是不是根节点,另外如果奇环只有一个的话,我们是可以修改非树边的,注意最后 +1。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,dep[N],vis[N],odd[N],even[N],ans,ff[N];
int tot,head[N];
struct node{
int to,nxt;
}edge[N<<1];
void addedge(int u,int v){
edge[tot]={v,head[u]};
head[u]=tot++;
}
void dfs(int u,int fa,int idx){
ff[u]=fa,dep[u]=dep[fa]+1,vis[u]=1;
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].to;
if((i^1)==idx)continue;
if(!vis[v]){
dfs(v,u,i);
odd[u]+=odd[v];
even[u]+=even[v];
}else{
if(dep[v]>dep[u])continue;
if((dep[u]-dep[v])&1)
even[u]++,even[v]--,even[0]++;
else
odd[u]++,odd[v]--,odd[0]++;
}
}
}
int main(){
memset(head,-1,sizeof head);
cin>>n>>m;
for(int i=1,u,v;i<=m;++i){
cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
for(int i=1;i<=n;++i){
if(!vis[i])dfs(i,0,-1);
}
for(int i=1;i<=n;++i){
if(!even[i]&&odd[i]==odd[0])ans++;
}
cout<<odd[0]<<endl;
if(odd[0]==1)ans++;
cout<<ans;
}

浙公网安备 33010602011771号