標籤:節點 const ons color soft ros 思路 for include
題意:
先給出一棵樹,然後再給出m條邊,把這m條邊連上,然後剪掉兩條邊,一條是原邊,一條是新邊,問有多少種方案能使圖不連通。
思路:
從原邊的角度看
1.樹加邊,一定成環,加一條(u,v)邊就有u->lca->v上的邊被覆蓋一次
2.當一條邊沒被覆蓋時,刪去該邊與任意一條新邊都能使圖不連通,即有m種方案
3.當一條邊被覆蓋1次時,刪去與該邊成環的新邊,即有1種方案
4.當一條邊被覆蓋1次以上時,沒有方案
用樹形dp,dp[i]表示第i號點與其父親相連的邊被覆蓋的次數。一條新邊(u,v)加入則++dp[u],++dp[v],dp[lca(u,v)]-=2,計算時從葉子結點向上累加,子節點的值加到父節點上,最後每個節點上的值就是覆蓋次數。
反思:
1.倍增求lca時不熟練。
2.計算時根節點不計算。
代碼:
1 #include<cstdio> 2 const int M=100005; 3 #define swap(x,y) t=x,x=y,y=t 4 int t,cnt,ans,v[M<<1],dp[M],dep[M],hea[M<<1],nex[M<<1],p[M][18]; 5 6 int read() 7 { 8 int x=0; char ch=getchar(); 9 while (ch<48 || ch>57) ch=getchar();10 while (ch>47 && ch<58) x=(x<<1)+(x<<3)+ch-48,ch=getchar();11 return x;12 }13 14 void add(int x,int y) { v[++cnt]=y,nex[cnt]=hea[x],hea[x]=cnt; }15 16 void dfs(int u,int x)17 {18 dep[u]=dep[p[u][0]=x]+1;19 for (int i=hea[u];i;i=nex[i])20 if (v[i]^x) dfs(v[i],u);21 }22 23 int lca(int x,int y)24 {25 if (dep[x]<dep[y]) swap(x,y);26 for (int i=17;~i;--i)27 if (dep[p[x][i]]>=dep[y]) x=p[x][i];28 if (x==y) return x;29 for (int i=17;~i;--i)30 if (p[x][i]^p[y][i]) x=p[x][i],y=p[y][i];31 return p[x][0];32 }33 34 void DFS(int u,int x)35 {36 for (int i=hea[u],y;y=v[i],i;i=nex[i])37 if (y^x) DFS(y,u),dp[u]+=dp[y];38 }39 40 int main()41 {42 int n=read(),m=read(),x,y,i,j;43 for (i=1;i<n;++i) x=read(),y=read(),add(x,y),add(y,x);44 dfs(1,0);45 for (i=1;i<18;++i)46 for (j=1;j<=n;++j)47 if (p[j][i-1]) p[j][i]=p[p[j][i-1]][i-1];48 for (i=1;i<=m;++i) ++dp[x=read()],++dp[y=read()],dp[lca(x,y)]-=2;49 DFS(1,0);50 for (i=2;i<=n;++i)51 if (!dp[i]) ans=ans+m;52 else if (dp[i]==1) ++ans;53 printf("%d\n",ans);54 return 0;55 }
poj 3417 Network 題解