题解:P11967 [GESP202503 八级] 割裂
八级最简单的一次考试。
我们来看这棵树,假设好点对是
但是,这题最多有
此时标记如下:
标记完了后我们就统计每个子树内的节点和,最终就变成这个样子:
这样,每个点对只作
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e6 + 10;
int n, q, u, v, a[N], fa[N][20], dep[N], cnt;
vector<int> g[N];
void dfs(int u, int f){
fa[u][0] = f;
dep[u] = dep[f] + 1;
for(int i = 1; i < 20; i++) fa[u][i] = fa[fa[u][i-1]][i-1];
for(int v: g[u]){
if(v == f) continue;
dfs(v, u);
}
}
int lca(int u, int v){
if(dep[u] < dep[v]) swap(u, v);
for(int i = 19; i >= 0; i--){
if((dep[u] - dep[v]) & (1 << i)) u = fa[u][i];
}
if(u == v) return u;
for(int i = 19; i >= 0; i--){
if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
void get_ans(int u, int f){
for(int v: g[u]){
if(v == f) continue;
get_ans(v, u);
a[u] += a[v];
}
}
int main(){
cin >> n >> q;
for(int i = 1; i < n; i++){
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
while(q--){
cin >> u >> v;
int w = lca(u, v);
a[u]++; a[v]++;
a[w]--; a[fa[w][0]]--;
}
get_ans(1, 0);
cin >> u >> v;
int w = lca(u, v);
while(u != w){
if(a[u] == 0) cnt++;
u = fa[u][0];
}
while(v != w){
if(a[v] == 0) cnt++;
v = fa[v][0];
}
if(a[u] == 0) cnt++;
cout << cnt;
return 0;
}