BZOJ_4238_电压_树上差分+dfs树
Description
你知道Just Odd Inventions社吗?这个公司的业务是“只不过是奇妙的发明(Just Odd Inventions)”。这里简称为JOI社。
JOI社的某个实验室中有着复杂的电路。电路由n个节点和m根细长的电阻组成。节点被标号为1~N
每个节点有一个可设定的状态【高电压】或者【低电压】。每个电阻连接两个节点,只有一端是高电压,另一端是低电压的电阻才会有电流流过。两端都是高电压或者低电压的电阻不会有电流流过。
某天,JOI社为了维护电路,选择了一根电阻,为了能让【只有这根电阻上的电流停止流动,其他M-1根电阻中都有电流流过】,需要调节各节点的电压。为了满足这个条件,能选择的电阻共有多少根?
对了,JOI社这个奇妙的电路是用在什么样的发明上的呢?这是公司内的最高机密,除了社长以外谁都不知道哦~
现在给出电路的信息,请你输出电路维护时可以选择使其不流的电阻的个数。
Input
第一行两个空格分隔的正整数N和M,表示电路中有N个节点和M根电阻。
接下来M行,第i行有两个空格分隔的正整数Ai和Bi(1<=Ai<=N,1<=Bi<=N,Ai≠Bi),表示第i个电阻连接节点Ai和节点Bi。
Output
输出一行一个整数,代表电路维护时可选择的使其不流的电阻个数。
Sample Input
4 4
1 2
2 3
3 2
4 3
1 2
2 3
3 2
4 3
Sample Output
2
HINT
可以选择第一根电阻或第四根电阻。
2<=N<=10^5
1<=M<=2*10^5
不保证图是连通的,不保证没有重边
首先把图中的边分成树边和非树边。把非树边分成偶环和奇环。
首先有最基本的性质1:偶环上的边不能拆,并且拆完之后不能有奇环。
性质2:如果图里只有一个奇环。可以选择一个非树边,否则不可以选择非树边,因为此时要么非树边在偶环里,要么拆掉这条非树边图中仍存在奇环。
性质3:选择的树边需要满足:被所有的奇环覆盖并且不被任何一个偶环覆盖。
于是树上差分即可。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 200050 int head[N],to[N<<1],nxt[N<<1],vis[N],cnt=1,n,m; int odd[N],even[N],fa[N],dep[N]; inline void add(int u,int v) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; } void dfs(int x,int y,int idx) { fa[x]=y; dep[x]=dep[y]+1; vis[x]=1; int i; for(i=head[x];i;i=nxt[i]) { if((i^1)==idx) continue; if(!vis[to[i]]) { dfs(to[i],x,i); even[x]+=even[to[i]]; odd[x]+=odd[to[i]]; }else { if(dep[to[i]]>dep[x]) continue; int d=dep[x]-dep[to[i]]; if(d&1) { even[x]++; even[to[i]]--; even[0]++; }else { odd[x]++; odd[to[i]]--; odd[0]++; } } } } int main() { scanf("%d%d",&n,&m); int i,x,y; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } for(i=1;i<=n;i++) { if(!vis[i]) { dfs(i,0,0); } } int ans=0; for(i=1;i<=n;i++) { if(fa[i]&&odd[i]==odd[0]&&!even[i]) ans++; } if(odd[0]==1) ans++; printf("%d ",ans); }