你知道 Just Odd Inventions 公司吗?这个公司的业务是「只不过是奇妙的发明 / Just Odd Inventions」。这里简称为 JOI 公司。
JOI 公司的某个实验室中有着复杂的电路。电路由 \(n\) 个节点和 \(m\) 根细长的电阻组成。节点编号为 \(1\) 到 \(n\) 。
每个节点可设定为两种电平之一:高电平或者低电平。每个电阻连接两个节点,只有一端是高电平,另一端是低电平的电阻才会有电流流过。两端都是高电平或者低电平的电阻不会有电流流过。
试求:有多少个电阻,可以通过调节各节点的电压,使得「没有电流流经该电阻,且其他 \(m-1\) 根电阻中都有电流流过」。
对了,JOI 公司这个奇妙的电路是用在什么样的发明上的呢?这是公司内的最高机密,除了社长以外谁都不知道哦~\(2\leq n\leq 10^5,1\leq m\leq 2\cdot 10^5\)
没有电流流经该电阻,且其他 \(m-1\) 根电阻中都有电流流过 .
如果这张图没有环 .
那么,图中的任意一条边都是可以的 .
如果这张图有环.
二分图与非二分图的区别本质是有无奇环 .
翻译一下,即为删掉这条边之后图为二分图,加上这条边图不是二分图 .
进一步的,说明,这条边在奇环上,并且,删掉这条边之后就不会存在奇环 .
考虑建出 \(dfs\) 树. \(dfs\) 树的一个特点就是每个非树边都是有子孙节点连向祖先节点的 .
此时,边就可以分为两种了,一种是非树边,一种是树边.
对于非树边,这条边必须要构成一个奇环,并且图中只能有一个奇环 . 否则,删除之后,此图还不是二分图.
对于树边,分析一下,必须是所有的奇环都包含了这条边 . 仅此而已吗?并不是,如果奇环上的一条边断掉了,并且存在一个偶环经过这条边,那么,这个奇环的一部分和这个偶环的一部分就会构成一个奇环 . 所以,当前边还不能在偶环上 .
分析完,奇环和偶环个数的求解可以用树上差分 .
时间复杂度 : \(\mathrm O(n+m)\)
空间复杂度 : \(\mathrm O(n+m)\)
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
int res=0;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return res;
}
inline void print(int res){
if(res==0){
putchar('0');
return;
}
int a[10],len=0;
while(res>0){
a[len++]=res%10;
res/=10;
}
for(int i=len-1;i>=0;i--)
putchar(a[i]+'0');
}
int n,m;
vector<pair<int,int> >e;
bool tree[200010],vis[100010];
vector<pair<int,int> >g[100010],tg[100010];
int fa[100010];
int dep[100010],sum[100010][2];
void dfs(int x){
vis[x]=true;
for(int i=0;i<(int)g[x].size();i++){
int to=g[x][i].first,id=g[x][i].second;
if(!vis[to]){
tree[id]=true;
tg[x].push_back(make_pair(to,id));
tg[to].push_back(make_pair(x,id));
dfs(to);
}
}
}
int tot=0;
queue<int>q;
void bfs(int r){
while(!q.empty())q.pop();
dep[r]=0;
q.push(r);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<(int)tg[x].size();i++){
int to=tg[x][i].first;
if(dep[to]==-1){
dep[to]=dep[x]+1;
q.push(to);
}
}
}
vector<int>vs;
q.push(r);
fa[r]=-1;
while(!q.empty()){
int x=q.front();
q.pop();
vs.push_back(x);
for(int i=0;i<(int)g[x].size();i++){
int to=g[x][i].first,id=g[x][i].second;
if((!tree[id])&&(dep[to]<dep[x])){
if((dep[x]-dep[to])%2==0){
tot++;
sum[x][1]++;
sum[to][1]--;
}
else{
sum[x][0]++;
sum[to][0]--;
}
}
}
for(int i=0;i<(int)tg[x].size();i++){
int to=tg[x][i].first;
if(dep[to]==dep[x]+1){
fa[to]=x;
q.push(to);
}
}
}
for(int i=(int)vs.size()-1;i>=0;i--){
int x=vs[i];
if(fa[x]!=-1){
sum[fa[x]][0]+=sum[x][0];
sum[fa[x]][1]+=sum[x][1];
}
}
}
int main(){
n=read();m=read();
for(int i=0;i<m;i++){
int u=read()-1,v=read()-1;
e.push_back(make_pair(u,v));
g[u].push_back(make_pair(v,i));
g[v].push_back(make_pair(u,i));
}
memset(dep,-1,sizeof(dep));
for(int i=0;i<n;i++){
if(!vis[i]){
dfs(i);
bfs(i);
}
}
int ans=0;
for(int i=0;i<m;i++){
int u=e[i].first,v=e[i].second;
if(!tree[i]){
if(dep[u]>dep[v])swap(u,v);
if(tot==1&&(dep[u]-dep[v])%2==0)ans++;
}
else{
if(dep[u]<dep[v])swap(u,v);
if(sum[u][1]==tot&&sum[u][0]==0)ans++;
}
}
print(ans);
putchar('\n');
return 0;
}
/*inline? ll or int? size? min max?*/