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