BZOJ4424

Description

给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成
一个二分图。

Input

第 1 行包含两个整数 n,m。分别表示点数和边数。
第 2 到 m+1 行每行两个数 x,y 表示有一条(x,y)的边。

Output

输出第一行一个整数,表示能删除的边的个数。
接下来一行按照从小到大的顺序输出边的序号。

Sample Input

4 4
1 2
1 3
2 4
3 4

Sample Output

4
1 2 3 4

HINT

100%的数据,n,m<=1000000

Source

考虑一个二分图的性质:没有奇环
在生成树上考虑每条非树边,如果它是奇环 就要选 否则不能选对应的树边 差分+1-1即可
注意特判环0/1个的情况
另外会PE 同时输出的时候还要判是否输出0
最后要sort一遍
[cpp]   view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include<bits/stdc++.h>  
  2.   
  3. using namespace std;  
  4.   
  5. const int maxn=1000010;  
  6.   
  7. int n,m,cnt,head[maxn],fa[maxn],dep[maxn],f[maxn][21],d[maxn];  
  8.   
  9. int s[maxn],tot,used,ans,g[maxn];  
  10.   
  11. bool vis[maxn];  
  12.   
  13. int findfa(int x) { return fa[x]==x?x:fa[x]=findfa(fa[x]); }  
  14.   
  15. struct Edge  
  16. {  
  17.     int u,v,flag;  
  18. }E[maxn];  
  19.   
  20. struct edge  
  21. {  
  22.     int to,nxt,id;  
  23. }e[maxn<<1];  
  24.   
  25. inline void addedge(int x,int y,int id)  
  26. {  
  27.     e[++cnt].to=y;  
  28.     e[cnt].nxt=head[x];  
  29.     head[x]=cnt;  
  30.     e[cnt].id=id;  
  31. }  
  32.   
  33. inline void add(int x,int y,int id) { addedge(x,y,id); addedge(y,x,id); }  
  34.   
  35. void build(int x)  
  36. {  
  37.     vis[x]=1;  
  38.     for(int i=head[x];i;i=e[i].nxt)  
  39.     {  
  40.         int y=e[i].to;  
  41.         if(f[x][0]!=y)  
  42.         {  
  43.             f[y][0]=x;  
  44.             dep[y]=dep[x]+1;  
  45.             d[y]=i;  
  46.             build(y);  
  47.         }  
  48.     }  
  49. }  
  50.   
  51. inline void init()  
  52. {  
  53.     for(int j=1;j<=20;j++)  
  54.         for(int i=1;i<=n;i++)  
  55.             f[i][j]=f[f[i][j-1]][j-1];  
  56. }  
  57.   
  58. inline void pushup(int &x,int d)  
  59. {  
  60.     for(int j=20;j>=0;j--)  
  61.         if(dep[x]-d>=(1<<j))  
  62.             x=f[x][j];  
  63. }  
  64.   
  65. inline int lca(int x,int y)  
  66. {  
  67.     if(dep[x]<dep[y]) swap(x,y);  
  68.     if(dep[x]^dep[y]) pushup(x,dep[y]);  
  69.     if(x==y) return x;  
  70.     for(int j=20;j>=0;j--)  
  71.         if(f[x][j]!=f[y][j])  
  72.             x=f[x][j],y=f[y][j];  
  73.     return f[x][0];  
  74. }  
  75.   
  76. void dfs(int x)  
  77. {  
  78.     vis[x]=1;  
  79.     for(int i=head[x];i;i=e[i].nxt)  
  80.         if(f[x][0]!=e[i].to)  
  81.             dfs(e[i].to),s[x]+=s[e[i].to];  
  82. }  
  83.   
  84. int main()  
  85. {  
  86.     scanf("%d%d",&n,&m);  
  87.     for(int i=1;i<=n;i++) fa[i]=i;  
  88.     for(int i=1;i<=m;i++)  
  89.     {  
  90.         scanf("%d%d",&E[i].u,&E[i].v);  
  91.         if(findfa(E[i].u)==findfa(E[i].v)) E[i].flag=1;  
  92.         else E[i].flag=0,fa[findfa(E[i].u)]=findfa(E[i].v),add(E[i].u,E[i].v,i);  
  93.     }  
  94.     for(int i=1;i<=n;i++) if(!vis[i]) build(i);  
  95.     init();  
  96.     for(int i=1;i<=m;i++)  
  97.         if(E[i].flag)  
  98.         {  
  99.             int LCA=lca(E[i].u,E[i].v);  
  100.             int f=-1;  
  101.             if(!((dep[E[i].u]+dep[E[i].v])&1)) f=1,tot++,used=i;  
  102.             s[E[i].u]+=f,s[E[i].v]+=f;  
  103.             s[LCA]-=f*2;  
  104.         }  
  105.     if(!tot)  
  106.     {  
  107.         printf("%d\n",m);  
  108.         for(int i=1;i<m;i++) printf("%d ",i); if(m) printf("%d",m);  
  109.         return 0;  
  110.     }  
  111.     memset(vis,0,sizeof(vis));  
  112.     for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);  
  113.     for(int i=1;i<=n;i++) if(s[i]==tot) g[++ans]=e[d[i]].id;  
  114.     if(tot==1) g[++ans]=used;  
  115.     sort(g+1,g+ans+1);  
  116.     printf("%d\n",ans);  
  117.     for(int i=1;i<ans;i++) printf("%d ",g[i]); if(ans) printf("%d",g[ans]);  
  118. }  

http://blog.csdn.net/wxh010910/article/details/53443973

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值