La pregunta original Portal
Una idea violenta correcta es atravesar el árbol, y luego, para cada punto, romper el borde entre él y su padre. Entonces eche un vistazo, conjunto de bordes E 2 E2Cuántas líneas en E 2 conectan los dos bloques conectados, cuente el número comocnt cntc n t
- cnt = cnt = 0 0 c n t=0 , que indicaE 2 E2Se puede seleccionar cada lado de E 2 y la respuesta se acumula enmmmetro
- cnt = cnt = 1 1 c n t=1 , entonces solo puede cortar ese lado, y la respuesta sumará 1
- cnt> 1 cnt> 1 c n t>1 , no se pueden romper los bordes
Cómo contar este cnt cntc n t ?
Se puede combinar violentamente, pero podemos marcar la diferencia
en elárbol.Para unE 2 E2Arista en E 2 (u, v) (u, v)( u ,v )
++delta[u],++delta[v],delta[lca(u,v)]-=2
Estadísticas directas
Hay un dicho, "Diez años de OI, dos juegos están vacíos, no abrir, veré a tus antepasados", pero una vez pensé que yo también tuve un día de esta trampa. Si no abro el ll, simplemente
pierdo 60 puntos.
Código:
#include <bits/stdc++.h>
#define maxn 200010
#define int long long
using namespace std;
struct Edge{
int to, next;
}edge[maxn << 1];
int num, head[maxn], delta[maxn], d[maxn], fa[maxn][25], n, m, ans;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void addedge(int x, int y){
edge[++num] = (Edge){
y, head[x]}, head[x] = num; }
void build(int u, int pre){
d[u] = d[pre] + 1, fa[u][0] = pre;
for (int i = 0; fa[u][i]; ++i) fa[u][i + 1] = fa[fa[u][i]][i];
for (int i = head[u]; i; i = edge[i].next){
int v = edge[i].to;
if (v != pre) build(v, u);
}
}
int lca(int u, int v){
if (d[u] < d[v]) swap(u, v);
for (int i = 20; i >= 0; --i) if (d[u] - (1 << i) >= d[v]) u = fa[u][i];
if (u == v) return u;
for (int i = 20; i >= 0; --i)
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
void dfs(int u, int pre){
for (int i = head[u]; i; i = edge[i].next){
int v = edge[i].to;
if (v == pre) continue;
dfs(v, u);
delta[u] += delta[v];
}
if (u == 1) return;
if (!delta[u]) ans += m;
else if (delta[u] == 1) ++ans;
}
signed main(){
freopen("pa.in", "r", stdin);
freopen("pa.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i < n; ++i){
int x = read(), y = read();
addedge(x, y), addedge(y, x);
}
build(1, 0);
for (int i = 1; i <= m; ++i){
int x = read(), y = read(), Lca = lca(x, y);
++delta[x], ++delta[y], delta[Lca] -= 2;
}
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}