BZOJ_4238_电压_树上差分+dfs树

Posted fcwww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ_4238_电压_树上差分+dfs树相关的知识,希望对你有一定的参考价值。

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

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\n",ans);
}

 

以上是关于BZOJ_4238_电压_树上差分+dfs树的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4238电压 DFS树

BZOJ_3252_攻略_线段树+dfs序

BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

BZOJ_1016_[JSOI2008]_最小生成树计数_(dfs+乘法原理)

BZOJ_1316_树上的询问_点分治

[bzoj4345][POI2016]Korale_堆_贪心_线段树_dfs