1. 程式人生 > 其它 >bzoj #4238 loj #2881「JOISC 2014 Day3」電壓

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?*/