1. 程式人生 > >poj 3417 Network 題解

poj 3417 Network 題解

define class tro 題意 clas family soft size ron

題意:

  先給出一棵樹,然後再給出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 題解