算法:
我们可以用树上差分的方法,求出一个非根节点有多少条路径到达他父亲(除了从那条直接连接的主要边),如果没有这样的路径,那么割掉这条主要边,然后去掉任意一个附加边即可,对答案贡献为m;如果有一条这样的路径,那么我们可以先去掉直接连接的边,然后断掉这一条通路即可,对答案贡献为1;如果这样的路径个数大于1,那么我们对于割这条主要边,是不存在任何一个方案满足答案的。直接模拟统计即可。
Code:
#include<iostream>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rep2(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
template<typename T> void read(T &num){scanf("%d",&num);}
template<typename T> void write(T x){printf("%d\n",x);}
int n,m;
struct wzy{
int nxt,vertice;
}edge[200010];
int head[100010];int len=0;
inline void add_edge(int x,int y){
edge[++len].nxt=head[x];edge[len].vertice=y;head[x]=len;return;
}
long long ans=0;
int dep[100010];int f[100010][17];int dif[100010];
inline void Pretreatment(int son,int father){
dep[son]=dep[father]+1;f[son][0]=father;
rep(i,1,16){f[son][i]=f[f[son][i-1]][i-1];}
for(int i=head[son];i;i=edge[i].nxt){
int nop=edge[i].vertice;
if(nop==father)continue;
Pretreatment(nop,son);
}
return;
}
inline int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
rep2(i,16,0){
if(dep[f[x][i]]>=dep[y]){x=f[x][i];}
}
if(x==y)return x;
rep2(i,16,0){
if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}
}
return f[x][0];
}
inline void solve(int son,int father){
for(int i=head[son];i;i=edge[i].nxt){
int nop=edge[i].vertice;
if(nop==father)continue;
solve(nop,son);dif[son]+=dif[nop];
}
if(son==1)return;
ans+=m*(dif[son]==0)+(dif[son]==1);
return;
}
int main(){
read(n);read(m);
rep(i,1,n-1){int x,y;read(x);read(y);add_edge(x,y);add_edge(y,x);}
Pretreatment(1,0);
rep(i,1,m){int x,y;read(x);read(y);dif[x]++;dif[y]++;dif[LCA(x,y)]-=2;}
solve(1,0);write(ans);
return 0;
}