bzoj4238 电压
首先先直接对图进行二染色,dfs染完色后,有的边为搜索树边,有的为非树边,当非树边连接的两头的点为异色的时候,那么很明显这条非树边和树边构成的环上的边必然不可能成为答案;如果非树边的两端的点同色,那么所有这种类型的非树边与树边构成的环的交集就是答案,对于一条这样的非树边,如果要使其变成二分图的合法边,那么必然会在其与树边构成的环中剔除掉一条边,这样树变成了两个部分,把其中一部分反色,在连上这条非树边,也是一个合法二分图,那么所有这种类型的边构成的环的交集,就是答案的可选集。
代码
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define N 500010 5 using namespace std; 6 int n,m,i,a[N],b[N],dp,p[N],pre[N],tt[N],id[N],vis[N],treeEdge[N]; 7 int deep[N],color[N],fa[N],sum[N],cnt,value[N]; 8 int s[N][21]; 9 void link(int x,int y,int z) 10 { 11 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;id[dp]=z; 12 } 13 void dfs(int x) 14 { 15 int i; 16 vis[x]=1; 17 i=p[x]; 18 while (i) 19 { 20 if (!vis[tt[i]]) 21 { 22 deep[tt[i]]=deep[x]+1; 23 treeEdge[id[i]]=1; 24 color[tt[i]]=1-color[x]; 25 fa[tt[i]]=x; 26 dfs(tt[i]); 27 } 28 i=pre[i]; 29 } 30 } 31 void gao(int x) 32 { 33 int i,tmp=0; 34 vis[x]=1; 35 i=p[x]; 36 while (i) 37 { 38 if (!vis[tt[i]]) 39 { 40 gao(tt[i]); 41 tmp+=sum[tt[i]]; 42 value[id[i]]=sum[tt[i]]; 43 } 44 i=pre[i]; 45 } 46 sum[x]+=tmp; 47 } 48 int lca(int x,int y) 49 { 50 if(deep[x]>deep[y])x^=y^=x^=y; 51 int i; 52 for(i=19;i>=0;i--) 53 { 54 if(deep[y]-deep[x]>=(1<<i)) 55 { 56 y=s[y][i]; 57 } 58 } 59 if(x==y)return x; 60 for(i=19;i>=0;i--) 61 { 62 if(s[x][i]!=s[y][i]) 63 { 64 x=s[x][i]; 65 y=s[y][i]; 66 } 67 } 68 return fa[x]; 69 } 70 71 int main() 72 { 73 scanf("%d%d",&n,&m); 74 for (i=1;i<=m;i++) 75 { 76 scanf("%d%d",&a[i],&b[i]); 77 link(a[i],b[i],i); 78 link(b[i],a[i],i); 79 } 80 for (i=1;i<=n;i++) if (!vis[i]) dfs(i); 81 for(i=1;i<=n;i++)s[i][0]=fa[i]; 82 for(int h=1;h<20;h++) 83 { 84 for(i=1;i<=n;i++) 85 { 86 s[i][h]=s[s[i][h-1]][h-1]; 87 } 88 } 89 for (i=1;i<=m;i++) 90 if ((!treeEdge[i])&&(color[a[i]]!=color[b[i]])) 91 { 92 sum[a[i]]--; 93 sum[b[i]]--; 94 sum[lca(a[i],b[i])]+=2; 95 } 96 for (i=1;i<=m;i++) 97 if ((!treeEdge[i])&&(color[a[i]]==color[b[i]])) 98 { 99 cnt++; 100 sum[a[i]]++; 101 sum[b[i]]++; 102 sum[lca(a[i],b[i])]-=2; 103 } 104 memset(vis,0,sizeof(vis)); 105 for (i=1;i<=n;i++) 106 if (!vis[i]) gao(i); 107 int ans=0; 108 for (i=1;i<=m;i++) 109 if ((treeEdge[i])&&(value[i]==cnt)) ans++; 110 if (cnt==1) ans++; 111 printf("%d\n",ans); 112 }