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;
}

posted @ 2019-10-13 22:15  wuhan2005  阅读(88)  评论(0编辑  收藏  举报