A-小王子
题意:对于题意可以分解为.
有n个点,由n-1条白色的边连接,同时又有着m条边.
因为这里说到了白色的边都不重复也不缠绕,显然是n-1条边构成树边.
然后有m条非树边。然后问我们删去一条树边和一条非树边使树分为两部分。这条边完全断开.
思路:参考来自:博客
我们可以从每条树边出发。
对于每条树边。
如果没有非树边覆盖到它.那么删去所有中任意的非树边都可以.即m种方案.
如果有一条非树边覆盖到它,那么只有删去这条树边才可以.即1种方案.
如果有两条及以上的非树边覆盖到它,那么删去非树边中的任意一条都不行,依旧会连通.所以此时方案为0.
统计树边的覆盖情况采用树上差分的边差分.
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int>G[N];
int fa[N][25],dep[N],sz[N],n,m,u,v;
void dfs(int u,int f)
{
fa[u][0]=f;
dep[u]=dep[f]+1;
for(int v:G[u]) if(v!=f) dfs(v,u);
}
void init()
{
dfs(1,1);
for(int k=1;k<=24;++k)
for(int i=1;i<=n;++i)
fa[i][k]=fa[fa[i][k-1]][k-1];
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int k=24;~k;--k){
if(dep[fa[u][k]]>=dep[v]) u=fa[u][k];
}
if(u==v) return u;
for(int k=24;~k;--k){
if(fa[u][k]!=fa[v][k]) u=fa[u][k],v=fa[v][k];
}
return fa[u][0];
}
long long ans;
void dfs2(int u,int f)
{
for(int v:G[u]){
if(v==f) continue;
dfs2(v,u);
sz[u]+=sz[v];
if(sz[v]==0) ans+=m;
else if(sz[v]==1) ans++;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n;++i){
scanf("%d%d",&u,&v);
G[u].push_back(v);G[v].push_back(u);
}
init();
//printf("%d\n",lca(4,5));
for(int i=1;i<=m;++i){
scanf("%d%d",&u,&v);
sz[u]++;sz[v]++;
sz[lca(u,v)]-=2;
}
dfs2(1,1);
printf("%lld\n",ans);
}