bzoj #4238 loj #2881「JOISC 2014 Day3」电压

你知道 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?*/

上一篇:数据结构与算法(Python版):时间复杂度和大O表示法


下一篇:【Codeforce 746 C】Bakry and Partitioning