• BZOJ4238 : 电压


    如果一条边可行,那么删掉这条边后,剩下的图是二分图且该边的两端点颜色相同。

    那么可行的边必然属于所有奇环的交集,且不属于任何偶环。

    随便取一棵生成树,对于一条非树边,它形成了环:

    若是偶环,则将环上的边都标记为不能选。

    若是奇环,则将环上的边经过的奇环数都加一。

    可以用树链剖分维护前缀和做到$O(mlog n)$。

    对于其它的环,都可以由以下三种情况得到:

    1.一个奇环异或一个偶环得到一个新的奇环,公共部分一定经过了偶环,即使不标记也会被舍去。

    2.一个奇环异或一个奇环得到一个新的偶环,新环上的边一定不属于所有奇环的交,即使不标记也会被舍去。

    3.一个偶环异或一个偶环得到一个新的偶环,公共部分一定经过了偶环且被标记过了,所以无需再次标记。

    因此只需要考虑所有两两之间异或可以表示出所有环的基环即可。

    #include<cstdio>
    #define N 300010
    int n,m,i,x,y,f[N],g[N],nxt[N<<1],v[N<<1],ed,son[N],size[N],d[N],dis[N],top[N],loc[N],dfn,s[2][N];
    int e[N][2],need[N],ban[N],cnt,ans;
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline void add(int x,int y){
      v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
      v[++ed]=x;nxt[ed]=g[y];g[y]=ed;
    }
    void dfs(int x,int y){
      size[x]=1,d[x]=d[f[x]=y]+1,dis[x]=dis[y]+(x<=n);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
        dfs(v[i],x);size[x]+=size[v[i]];
        if(size[v[i]]>size[son[x]])son[x]=v[i];
      }
    }
    void dfs2(int x,int y){
      top[x]=y;loc[x]=++dfn;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
    }
    inline void modify(int x,int y,int p){
      for(;top[x]!=top[y];x=f[top[x]]){
        if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
        s[p][loc[top[x]]]++,s[p][loc[x]+1]--;
      }
      if(d[x]<d[y]){int z=x;x=y;y=z;}
      s[p][loc[y]]++,s[p][loc[x]+1]--;
    }
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    int main(){
      read(n),read(m);
      for(i=1;i<=n;i++)f[i]=i;
      for(i=1;i<=m;i++){
        read(x),read(y),e[i][0]=x,e[i][1]=y;
        if(F(x)!=F(y))f[f[x]]=f[y],add(x,i+n),add(y,i+n);else need[i]=1;
      }
      for(i=1;i<=n;i++)if(!d[i])dfs(i,0),dfs2(i,i);
      for(i=1;i<=m;i++)if(need[i]){
        x=e[i][0],y=e[i][1];
        if((dis[x]&1)^(dis[y]&1))ban[i]=1,modify(x,y,0);else modify(x,y,1),cnt++;
      }
      for(i=2;i<=dfn;i++)s[0][i]+=s[0][i-1],s[1][i]+=s[1][i-1];
      for(i=1;i<=m;i++)if(need[i]){
        if(!ban[i]&&cnt==1)ans++;
      }else{
        if(!s[0][loc[i+n]]&&s[1][loc[i+n]]==cnt)ans++;
      }
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    JSP一个简单的项目实现教程
    多个Excel文件快速导入到DB里面
    NotePad++左侧导航
    简单实用JSTL标签库
    Eclipse导入现有项目
    Java工具Eclipse
    winform窗体只能放大不能缩小
    ref out

    数组
  • 原文地址:https://www.cnblogs.com/clrs97/p/4737869.html
Copyright © 2020-2023  润新知