题意:
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;
}