zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    }
    
  • 相关阅读:
    JAVA基础——编程练习(二)
    JAVA基础——面向对象三大特性:封装、继承、多态
    JVM内存
    50. Pow(x, n) (JAVA)
    47. Permutations II (JAVA)
    46. Permutations (JAVA)
    45. Jump Game II (JAVA)
    43. Multiply Strings (JAVA)
    42. Trapping Rain Water (JAVA)
    41. First Missing Positive (JAVA)
  • 原文地址:https://www.cnblogs.com/suika/p/9023008.html
Copyright © 2011-2022 走看看