考察:LCA + 枚举
完全不会...LCA真难....
思路:
很容易看出两个分为两段的方式:
- 附加边加上成环后,环上去掉一个树边和一个非树边.
- 未成环的树边去掉一个边,然后任意去掉一个非树边.
设d[x] 表示 x点到其父节点的边上要去掉d[x]条非树边才断.
考虑枚举非树边,对于非树边环上的每一个树边.都需要去掉一个树边才能断.因此环上树边d[x]+1.如何快速将环上所有边+1? 这就涉及了LCA.
1 #include <iostream> 2 #include <cstring> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 const int N = 100010,M = 200010; 7 int h[N],idx,n,m,p[N],depth[N],fa[N][19],d[N]; 8 struct Road{ 9 int fr,to,ne; 10 }road[N<<1]; 11 void add(int a,int b) 12 { 13 road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 14 } 15 void bfs(int s) 16 { 17 queue<int> q; 18 memset(depth,0x3f,sizeof depth); 19 depth[0] = 0,depth[s] = 1; 20 q.push(s); 21 while(q.size()) 22 { 23 int u = q.front(); 24 q.pop(); 25 for(int i=h[u];~i;i=road[i].ne) 26 { 27 int v = road[i].to; 28 if(depth[v]>depth[u]+1) 29 { 30 depth[v] = depth[u]+1; 31 q.push(v); 32 fa[v][0] = u; 33 for(int j=1;j<=17;j++) 34 fa[v][j] = fa[fa[v][j-1]][j-1]; 35 } 36 } 37 } 38 } 39 int lca(int a,int b) 40 { 41 if(depth[a]<depth[b]) swap(a,b); 42 for(int i=17;i>=0;i--) 43 if(depth[fa[a][i]]>=depth[b]) a = fa[a][i]; 44 if(a==b) return a; 45 for(int i=17;i>=0;i--) 46 if(fa[a][i]!=fa[b][i]) a = fa[a][i],b = fa[b][i]; 47 return a = fa[a][0]; 48 } 49 int dfs(int u,int fa) 50 { 51 int res = 0; 52 for(int i=h[u];~i;i=road[i].ne) 53 { 54 int v = road[i].to; 55 if(v==fa) continue; 56 res+=dfs(v,u); 57 if(d[v]==1) res++; 58 else if(!d[v]) res+=m; 59 d[u]+=d[v]; 60 } 61 return res; 62 } 63 int main() 64 { 65 scanf("%d%d",&n,&m); 66 memset(h,-1,sizeof h); 67 for(int i=1;i<n;i++) 68 { 69 int a,b; scanf("%d%d",&a,&b); 70 add(a,b); add(b,a); 71 } 72 bfs(1); 73 for(int i=1;i<=m;i++) 74 { 75 int a,b; scanf("%d%d",&a,&b); 76 d[a]+=1,d[b]+=1; 77 d[lca(a,b)]-=2; 78 } 79 printf("%d\n",dfs(1,-1)); 80 return 0; 81 }