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\n",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\n",qnt); for(int i=1;i<=qnt;i++)printf("%d ",q[i]); return 0; }