题意:
n个点m条无向边
下面n-1行给定原树
m行给定新边
问删一条老边和新边使得图不连通的方法
首先,对于一条新边(u,v),加入后 成环 u, v, LCA(u,v)
所以删除新边(a,b)以及这个环上的没有被其他环覆盖的边
即可分成两部分。所以问题转化为求每条边被环覆盖的次数
设dp[x]表示x所在的父边被 新边覆盖的次数
引进一条新边(a,b)后,dp[a]++,dp[b]++
而这个环上的其他边的统计可以用treeDP解决,即for(v)
dp[u]+=dp[v]
注意到LCA(a,b)的父边是不在环上的,所以每次引进新边(a,b),dp[LCA[a,b]]-=2
最后,if(dp[i]==1)ans++ 删除该边及覆盖它的那个环
if(dp[i]==0)ans+=M 表明这条树边是桥,删除它及任意一条新边都可以
#include<string.h> #include<queue> #include<stdio.h> #include<iostream> #include<math.h> using namespace std; #define N 300100 inline int Max(int a, int b){return a>b?a:b;} struct Edge{ int from, to, nex; }edge[N<<1]; int head[N], edgenum ; void addedge(int u, int v){ Edge E ={ u, v, head[u]}; edge[ edgenum ] = E; head[u] = edgenum++; } int n, time; int first[N], index[N<<1], deep[N<<1], dis[N]; void DFS(int u, int dep){ index[time] = u; deep [time] = dep; time++; for(int i = head[u]; i!=-1; i = edge[i].nex) { int v = edge[i].to; if(first[v] == 0) { first[v] = time; dis[v] = dis[u] + 1; DFS(v, dep+1); index[time] = u; deep [time++] = dep; } } } int dp[N][20]; void RMQ_init(int n){ for(int i = 1;i <= n; i++) dp[i][0] = i; for(int j = 1;1<<j <= n; j++) { int k = 1<<(j-1); for(int i = 1; i + k < n; i++) { if(deep[ dp[i][j-1] ]<= deep[ dp[i+k][j-1] ]) dp[i][j] = dp[i][j-1]; else dp[i][j] = dp[i+k][j-1]; } } } int RMQ(int a, int b){ int Dis = Max(a-b, b-a) + 1; int k = log(double(Dis)) / log(2.0); if(deep[ dp[a][k] ] <= deep[ dp[b-(1<<k)+1][k] ]) return dp[a][k]; else return dp[b-(1<<k)+1][k]; } int LCA(int u, int v){ int fu = first[u], fv = first[v]; return fu <= fv ? index[ RMQ(fu,fv) ] : index[ RMQ(fv,fu) ]; } int num[N]; void treedp(int u, int p) { for(int i = head[u]; i!=-1;i = edge[i].nex) { int v = edge[i].to; if(v==p)continue; treedp(v, u); num[u] += num[v]; } } int main() { int i, m, u, v; int root = 1; while(~scanf("%d%d",&n,&m)) { memset(head, -1, sizeof(head)); edgenum = 0; memset(first, 0, sizeof(first)); memset(num, 0, sizeof(num)); for(i = 1; i < n;i ++) { scanf("%d %d",&u,&v); addedge(u, v); addedge(v, u); } time = 1; first[root] = 1; dis[root] = 0; DFS(1, 0); RMQ_init(time-1); for(i=0;i<m;i++) { scanf("%d %d",&u,&v); num[u]++; num[v]++; num[LCA(u,v)] -= 2; } treedp(1,1); int ans = 0; for(i = 2; i <= n; i++) if(num[i] == 0)ans += m; else if(num[i] == 1)ans++; printf("%d\n",ans); } return 0; }