这题的意思是给N个点,新建M条边。先给一幅图,有N-1条边,然后给新建边M条,问删去一条原有边,一条新建边,有几种方法把图分成两块。这题思路是这样的,新建边与新建边两点的先祖节点形成的环上的边加1,因为新建边保护了环上的边,使得断了后图不会分成两块,所以当原有边次数为1时,只有断保护它的新建边才会使图分成两部分,如果原有图的边为零,因为无新建边保护,所以断开任意新建边都可以使图分成两部分,若次数大于1,无论怎样都不会使图分成两部分。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define maxn 100005
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
int head[maxn], qhead[maxn], lca[maxn], dp[maxn], qeagenum, eagenum;
bool vis[maxn], vis2[maxn];
struct eage
{
int to;
int next;
}eg[maxn * 2];
void add(int u, int v)
{
eg[eagenum].to = v;
eg[eagenum].next = head[u];
head[u] = eagenum++;
return;
}
struct qeage
{
int to;
int num;
int next;
}qeg[maxn * 2];
void qadd(int u, int v, int num)
{
qeg[qeagenum].to = v;
qeg[qeagenum].num = num;
qeg[qeagenum].next = qhead[u];
qhead[u] = qeagenum++;
return;
}
void inits()
{
mem(vis, 0);
mem(vis2, 0);
mem(dp, 0);
mem(lca, 0);
mem(head, -1);
mem(qhead, -1);
eagenum = 0;
qeagenum = 0;
return;
}
int finds(int a)
{
return a == lca[a] ? a : finds(lca[a]);
}
void tarjan(int a)
{
lca[a] = a;
vis[a] = 1;
int i, v;
for(i = head[a];i != -1;i = eg[i].next)
{
v = eg[i].to;
if(vis[v])
continue;
tarjan(v);
lca[v] = a;
}
for(i = qhead[a];i != -1;i = qeg[i].next)
{
v = qeg[i].to;
if(vis[v]&&!vis2[qeg[i].num])
{
vis2[qeg[i].num] = 1;
dp[finds(v)] -= 2;
}
}
return;
}
void DP(int u)
{
vis[u] = 1;
for(int i = head[u];i != -1;i = eg[i].next)
{
int v = eg[i].to;
if(!vis[v])
{
DP(v);
dp[u] += dp[v];
}
}
return;
}
int main(int argc, char *argv[])
{
int n, m, qn, u, v, ans;
while(~scanf("%d%d", &n, &m))
{
inits();
ans = 0;
for(int i = 0;i < (n - 1);i++)
{
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
for(int i = 0;i < m;i++)
{
scanf("%d%d", &u, &v);
qadd(u, v, i);
qadd(v, u, i);
dp[u]++;
dp[v]++;
}
tarjan(1);
mem(vis, 0);
DP(1);
for(int i = 2;i <= n;i++)
{
if(dp[i] == 1)
ans += 1;
else if(!dp[i])
ans += m;
}
printf("%d\n", ans);
}
return 0;
}