ABC298Ex 题解
sunkuangzheng
·
·
题解
【题目大意】
**【题解】**
一遍过编译一遍过样例一遍 AC,写这题真的太舒服啦!!111
考虑我们把点分为两种类型:距离 $u$ 近和距离 $v$ 近。容易发现两部分各自构成连通块,且分界点是 $u,v$ 的路径中点,那么分开计算贡献。为了方便,以下令 $dep_u \ge dep_v,d = \operatorname{mid}(u,v),l = \operatorname{lca}(u,v)$。计算 $d,l$ 可以简单倍增完成。
$\operatorname{dis}(u,v) = dep_u+dep_v-2dep_{\operatorname{lca}(u,v)}$,显然前两部分可以直接算,最后一部分分类计算。 $T_d$ 指的是 $d$ 的子树。
- 距离 $u$ 更近的点都在 $d$ 的子树里,也即求 $\sum \limits_{v \in T_d} dep_{{\operatorname{lca}(u,v)}}$,枚举 $\operatorname{lca}(u,v)$,考虑有多少符合条件的 $v$,容易发现这个和式的值等于 $u \to d$ 的链上 $siz_u$ 的和,加上 $(dep_d-1)siz_u$。
- 距离 $v$ 更近的点都在 $d$ 的子树外。我们先计算 $\sum \limits_{i=1}^n dep_{\operatorname{lca}(u,i)}$,再减去 $i \in T_d$ 部分 $i$ 的贡献。第一部分的计算和上面一样,第二部分由于 $d$ 子树内任意点和 $v$ 的 $\operatorname{lca}$ 都是 $l$,所以贡献是 $-siz_d \cdot dep_{l}$。
据此计算即可。时间复杂度 $\mathcal O((n+q) \log n)$。
```cpp
/**
* author: sunkuangzheng
* created: 16.02.2024 20:17:27
**/
#include<bits/stdc++.h>
#ifdef DEBUG_LOCAL
#include <mydebug/debug.h>
#endif
using ll = long long;
const int N = 5e5+5;
using namespace std;
int T,n,fa[N][22],siz[N],dep[N],u,v,q; ll sm[N],sum; vector<int> g[N];
void dfs(int u,int f){
fa[u][0] = f,siz[u] = 1,dep[u] = dep[f] + 1,sum += dep[u];
for(int i = 1;i <= __lg(dep[u]);i ++) fa[u][i] = fa[fa[u][i-1]][i-1];
for(int v : g[u]) if(v != f) dfs(v,u),siz[u] += siz[v];
}void dfs2(int u,int f){sm[u] = sm[f] + siz[u]; for(int v : g[u]) if(v != f) dfs2(v,u);}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
while(dep[u] > dep[v]) u = fa[u][__lg(dep[u] - dep[v])];
for(int i = __lg(dep[u]);i >= 0;i --) if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
return (u == v ? u : fa[u][0]);
}int kfa(int u,int k){
for(int i = __lg(dep[u]);i >= 0;i --) if((k >> i) & 1) u = fa[u][i];
return u;
}int dis(int u,int v){return dep[u] + dep[v] - 2 * dep[lca(u,v)];}
void los(){
cin >> n;
for(int i = 1;i < n;i ++) cin >> u >> v,g[u].push_back(v),g[v].push_back(u);
dfs(1,0),dfs2(1,0);
for(cin >> q;q --;){
if(cin >> u >> v,dep[u] < dep[v]) swap(u,v);
int di = dis(u,v),d = kfa(u,di / 2);
auto calc = [&](int u,int v){return sm[v] - sm[fa[u][0]];};
ll k = calc(d,u) + 1ll * siz[d] * (dep[d] - 1),p = calc(1,v) - 1ll * siz[d] * dep[lca(u,v)];
cout << 1ll * dep[u] * siz[d] + 1ll * dep[v] * (n - siz[d]) + sum - 2 * (k + p) << "\n";
}
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(T = 1;T --;) los();
}
```