1. 程式人生 > >CF 19E Fairy——樹上差分

CF 19E Fairy——樹上差分

contest con spa pre bool 樹邊 {} algorithm turn

題目: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; }

CF 19E Fairy——樹上差分