zoukankan      html  css  js  c++  java
  • CF 19E Fairy——树上差分

    题目:http://codeforces.com/contest/19/problem/E

    去掉一条边,使无向图变成二分图。

    该边应该被所有奇环经过,且不被偶环经过。

      因为一条非树边一定只在一个环里。所以一条既被所有奇环经过又被偶环经过的边是树边。如果把它去掉,将无法处理包含它的那个偶环的非树边和包含它的某个奇环的非树边加上两段树边所构成的奇环。

    找这样的边,弄一个边上的树上差分就行了。

    可以模仿kruscal用并查集弄一个生成树。不过dfs其实也行。

    注意图可能不连通。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e4+5;
    int n,m,c[N][2],fa[N],head[N],t[N<<1],next[N<<1],tot;
    int hd[N],xnt,col[N],cnt,pa[N],prbh,bh[N<<1],q[N],qnt;
    bool vis[N];
    struct Ed{
      int nxt,to,bh;Ed(int n=0,int t=0,int b=0):nxt(n),to(t),bh(b) {}
    }ed[N<<1];
    int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
    void add(int x,int y,int b)
    {
      ed[++xnt]=Ed(hd[x],y,b);hd[x]=xnt;
      ed[++xnt]=Ed(hd[y],x,b);hd[y]=xnt;
    }
    void dfs(int cr,int f)
    {
      vis[cr]=1;
      for(int i=head[cr],v;i;i=next[i])
        if(col[v=t[i]])
          {
        int f0=find(v),d=(col[cr]==col[v]);
        if(d){cnt++;if(cnt==1)prbh=bh[i];}
        c[cr][d]++;c[v][d]++;c[f0][d]-=2;
          }
      for(int i=hd[cr];i;i=ed[i].nxt)
        if(ed[i].to!=f)
          {
        col[ed[i].to]=3-col[cr];dfs(ed[i].to,cr);
          }
      fa[cr]=f;
    }
    void dfsx(int cr,int f,int eb)
    {
      vis[cr]=1;
      for(int i=hd[cr],v;i;i=ed[i].nxt)
        if((v=ed[i].to)!=f)
          {
        dfsx(v,cr,ed[i].bh);
        c[cr][0]+=c[v][0];c[cr][1]+=c[v][1];
          }
      if(c[cr][1]==cnt&&!c[cr][0])q[++qnt]=eb;
    }
    int main()
    {
      scanf("%d%d",&n,&m);int x,y;
      for(int i=1;i<=n;i++)fa[i]=i;
      for(int i=1;i<=m;i++)
        {
          scanf("%d%d",&x,&y);
          if(find(x)!=find(y))
        {
          add(x,y,i);
          fa[find(x)]=find(y);
        }
          else{
        t[++tot]=y;next[tot]=head[x];head[x]=tot;bh[tot]=i;
        t[++tot]=x;next[tot]=head[y];head[y]=tot;bh[tot]=i;
          }
        }
      for(int i=1;i<=n;i++)fa[i]=i;
      for(int i=1;i<=n;i++) if(!vis[i])
          col[i]=1,dfs(i,0);
      if(!cnt)
        {
          printf("%d
    ",m);
          for(int i=1;i<=m;i++)printf("%d ",i);return 0;
        }
      if(cnt==1)q[++qnt]=prbh;
      memset(vis,0,sizeof vis);
      for(int i=1;i<=n;i++) if(!vis[i])dfsx(i,0,0);
      sort(q+1,q+qnt+1);
      printf("%d
    ",qnt);
      for(int i=1;i<=qnt;i++)printf("%d ",q[i]);
      return 0;
    }
  • 相关阅读:
    Linux rpm 安装MySQL
    AOP 底层实现原理
    7 AOP
    HTTP 协议
    Oracle JDBC 标准连接实例
    Oracle JDBC 连接池
    Anaconda XGBoost安装
    Anaconda Spyder 导入自定义函数(模块)
    Hive常用sql
    决策树之信息增益计算模拟
  • 原文地址:https://www.cnblogs.com/Narh/p/9278306.html
Copyright © 2011-2022 走看看