東方14ACM小組水題0027 會議召開 樹

題目鏈接

http://west14.openjudge.cn/verywater/0027/

分析

補集轉化,關鍵在於求出有多少場會議不需要額外場地;

假設已確定兩場會議的位置,若第三場會議的位置在這兩點的路徑上,是符合要求的;

而在兩端確定的情況下,這樣的點只有兩端間路徑長度 1-1 個;

統計出所有路徑的長度再減去路徑數量即爲答案;

每條邊會對所有路徑長度之和貢獻 size[v](nsize[v])size[v] * (n - size[v])

size[v]size[v] 是以該邊深度較大點爲根的子樹大小;

路徑數量則可以在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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章