P9194 [USACO23OPEN] Triples of Cows P 题解

Description

给定一棵初始有 nn 个点的树。

在第 ii 天,这棵树的第 ii 个点会被删除,所有与点 ii 直接相连的点之间都会两两连上一条边。你需要在每次删点发生前,求出满足 (a,b)(a,b) 之间有边,(b,c)(b,c) 之间有边且 aca\not=c有序三元组 (a,b,c)(a,b,c) 对数。

n2×105n\leq 2\times 10^5

Solution

考虑把每个原图中的点看成白点,边看成黑点,原图中有连边的两个点就向他们对应的黑点连边。

那么每次删点操作就相当于把一个白点的所有相邻黑点合并,并且删除这个黑点。

所以所有 (a,b,c)(a,b,c) 可以看成 (a,x,b,y,c)(a,x,b,y,c),其中 xxa,ba,b 连边对应的黑点,yyb,cb,c 连边对应的黑点。

容易发现把 nn 作为根可以保证图始终是个树。

sxs_x 表示 xx 的儿子数,txt_x 表示 xx 儿子的 ss 之和,wxw_x 表示 xx 儿子的 tt 之和。然后考虑分类讨论。

首先如果 x=yx=y,答案就是 x为黑点(sx+1)sx(sx1)\sum_{x为黑点}{(s_x+1)s_x(s_x-1)}

如果 xyx\neq y 但是 x,yx,y 都是 bb 的儿子,答案就是 b为白点(tb2xson(b)sx2)\sum_{b为白点}{\left(t_b^2-\sum_{x\in son(b)}{s_x^2}\right)}

最后就是 xyx\neq yx,yx,y 一个是 bb 的儿子,一个是 bb 的父亲。

答案就是 2x是黑点sxwx2\sum_{x是黑点}{s_x w_x}

把所有的加起来就是:

x是黑点sx3sx2sx+2sxwx+y是白点ty2\sum_{x是黑点}{s_x^3-s_x^2-s_x+2s_x w_x}+\sum_{y是白点}{t_y^2}

每次合并的时候用并查集维护即可。

时间复杂度:O(nlogn)O(n\log n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 4e5 + 5;

int n;
int64_t ans;
int fa[kMaxN], s[kMaxN], t[kMaxN], w[kMaxN];
std::vector<int> G[kMaxN];

struct DSU {
int fa[kMaxN];

void init(int n) { std::iota(fa + 1, fa + 1 + n, 1); }

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
} dsu;

void dfs(int u) {
for (auto v : G[u]) {
if (v == fa[u]) continue;
fa[v] = u, ++s[u];
dfs(v);
t[u] += s[v], w[u] += t[v];
}
}

int64_t getcnt(int u) {
if (!u) return 0;
else if (u <= n) return (int64_t)t[u] * t[u];
else return (int64_t)s[u] * s[u] * s[u] - (int64_t)s[u] * s[u] - s[u] + (int64_t)2 * s[u] * w[u];
}

void work(int u) {
int ffa = dsu.find(fa[u]), fffa = dsu.find(fa[ffa]), ffffa = dsu.find(fa[fffa]);
ans -= getcnt(u) + getcnt(ffa) + getcnt(fffa) + getcnt(ffffa);
--s[ffa], --t[fffa], --w[ffffa];
for (auto v : G[u]) {
if (v == fa[u]) continue;
int fv = dsu.find(v);
dsu.fa[fv] = ffa;
ans -= getcnt(fv);
s[ffa] += s[fv], t[ffa] += t[fv], w[ffa] += w[fv];
--t[ffa], w[ffa] -= s[fv];
--w[fffa], w[fffa] += t[fv], t[fffa] += s[fv];
w[ffffa] += s[fv];
}
ans += getcnt(ffa) + getcnt(fffa) + getcnt(ffffa);
}

void dickdreamer() {
std::cin >> n;
for (int i = 1; i < n; ++i) {
int u, v;
std::cin >> u >> v;
G[u].emplace_back(n + i), G[n + i].emplace_back(u);
G[v].emplace_back(n + i), G[n + i].emplace_back(v);
}
dfs(n);
dsu.init(2 * n - 1);
for (int i = 1; i <= 2 * n - 1; ++i)
ans += getcnt(i);
for (int i = 1; i <= n; ++i) {
std::cout << ans << '\n';
work(i);
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P9194 [USACO23OPEN] Triples of Cows P 题解
https://sobaliuziao.github.io/2023/11/09/post/5d561156.html
作者
Egg_laying_master
发布于
2023年11月9日
许可协议