luoguP5002 专心OI-找祖先
对于每一个需要统计以它作为\(lca\)的点\(u\),求出他的每一个子树的大小:
\(1.\) 有一个点是\(u\)
$$ans1\ =\ (sz[u]\ <<\ 1)\ +\ 1$$
\(2.\) 两个点均不为\(u\)
\[\begin{eqnarray} ans2&=&(\sum sz[son[u]])^2\ -\ \sum sz[son[u]]^2\\&=&(sz[u]\ -\ 1)^2\ -\ \sum sz[son[u]]^2 \end{eqnarray}
\]
\[\begin{eqnarray} \therefore ans[i]&=&ans2\ -\ ans1\\&=&sz[u]^2\ -\ \sum sz[son[u]]^2\end{eqnarray}
\]
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int O = 5e4 + 10;
template<class TT>
il TT read() {
TT o = 0, fl = 1; char ch = getchar();
while (!isdigit(ch)) fl ^= ch == '-', ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl ? o : -o;
}
struct Edge {int to, nt;}e[O << 1];
int n, r, m, head[O], p[O], sz[O], sum[O], cnt;
il void add(int u, int v) {
e[++cnt] = (Edge){v, head[u]};
head[u] = cnt;
}
il void getsz(int u, int fa) {
sz[u] = 1;
for (int i = head[u]; i; i = e[i].nt) {
int v = e[i].to;
if(v == fa) continue;
getsz(v, u);
sz[u] += sz[v];
sum[u] += sz[v] * sz[v];
}
}
int main() {
n = gi(), r = gi(), m = gi();
for (int i = 1; i < n; ++i) {
int u = gi(), v = gi();
add(u, v); add(v, u);
}
getsz(r, -1);
while (m--) {
int u = gi();
printf("%d\n", sz[u] * sz[u] - sum[u]);
}
return 0;
}