題目鏈接
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;
}