bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【樹形dp】
阿新 • • 發佈:2018-07-23
return spa namespace iostream name != http cst main
參考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 這個找奇偶環的dp1真是巧妙,感覺像tarjan一樣
首先分情況討論,如果沒有奇環,每條邊都可以刪;如果有一個奇環,奇環上隋邊山;否則,刪被所有奇環覆蓋且沒被任何一個偶環覆蓋的邊
那麽重點就是怎樣找到所有的奇環和偶環
用樹形dp來搞,設f[i]記錄經過第i條邊的奇環數,g[i]記錄經過第i條邊的偶環數,因為是邊的編號而存的是雙向邊,所以dp的時候用i>>1表示
然後隨便dfs出一棵樹,對於其他的返祖邊如果是奇環的話f[i]++,偶環同理,並且加到父親上
然後如果是返祖邊的返祖邊要減掉,因為已經統計過了
#include<iostream> #include<cstdio> using namespace std; const int N=2000005; int n,m,cnt=1,h[N],con,ans[N],f[N],g[N],p[N],q[N],top,tot; bool v[N]; struct qwe { int ne,to; }e[N]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } void dfs(int u,int fa) { v[u]=1; p[u]=++top; for(int i=h[u];i;i=e[i].ne) if(q[i]!=-1) { if(!v[e[i].to]) { q[i]=q[i^1]=-1; dfs(e[i].to,i>>1); f[fa]+=f[i>>1]; g[fa]+=g[i>>1]; } else { if(q[i]==1) f[fa]--; if(q[i]==2) g[fa]--; if(q[i]==0) { if((p[u]-p[e[i].to])&1) g[fa]++,q[i]=q[i^1]=2; else f[fa]++,q[i]=q[i^1]=1,con++; } } } top--; } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(); add(x,y),add(y,x); } for(int i=1;i<=n;i++) if(!v[i]) dfs(i,0); if(con==0) { tot=m; for(int i=1;i<=m;i++) ans[i]=i; } else { for(int i=1;i<=m;i++) if((f[i]==con&&g[i]==0)||(con==1&&q[i<<1]==1)) ans[++tot]=i; } printf("%d\n",tot); for(int i=1;i<=tot;i++) printf("%d ",ans[i]); return 0; }
bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【樹形dp】