题目链接
http://west14.openjudge.cn/verywater/0027/
分析
补集转化,关键在于求出有多少场会议不需要额外场地;
假设已确定两场会议的位置,若第三场会议的位置在这两点的路径上,是符合要求的;
而在两端确定的情况下,这样的点只有两端间路径长度 个;
统计出所有路径的长度再减去路径数量即为答案;
每条边会对所有路径长度之和贡献 ;
是以该边深度较大点为根的子树大小;
路径数量则可以在DFS某点时,用新子树数量乘已有子树数量(包括该点)累加得到。
AC代码
#include <cstdio>
inline int read() {
int num = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9')
num = num * 10 + c - '0', c = getchar();
return num;
}
const int maxn = 1e5 + 5;
int head[maxn], eid;
struct Edge {
int v, next;
} edge[2 * maxn];
inline void insert(int u, int v) {
edge[++eid].v = v;
edge[eid].next = head[u];
head[u] = eid;
}
int n, size[maxn];
long long ans = 0;
void dfs(int u, int fa) {
size[u] = 1;
for (int p = head[u]; p; p = edge[p].next) {
int v = edge[p].v;
if (v == fa) continue;
dfs(v, u);
ans -= 1ll * size[v] * (n - size[v]) - 1ll * size[u] * size[v];
size[u] += size[v];
}
}
int main() {
n = read();
for (int i = 1; i < n; ++i) {
int u = read(), v = read();
insert(u, v), insert(v, u);
}
ans = 1ll * n * (n - 1) * (n - 2) / 6;
dfs(0, -1);
printf("%lld", ans);
return 0;
}