CF1712F Triameter 题解

Description

你有一棵有 nn 个点的树,树上的每条边权值都为 11。现在有 qq 次询问,每次询问一个整数 xx,并将叶子结点全部相连上权值为 xx 的边(操作不会保留)。问每次操作后图的直径是多少。图的直径定义为 max1u<vnd(u,v)\underset{1\leq u<v\leq n}{\max}d(u,v)

3n106,1q103\leq n\leq 10^6,1\leq q\leq 10

Solution

考虑转化一下 d(u,v)d(u,v)

hih_i 表示 ii 到叶子节点的最短距离,那么 d(u,v)d(u,v) 就等于 min{dist(u,v),hu+hv+x}\min\{\text{dist}(u,v),h_u+h_v+x\}

然后枚举一下 uuvvLCA\text{LCA},设它为 kk。那么 d(u,v)=min{depu+depv2×depk,hu+hv+x}d(u,v)=\min\{\text{dep}_u+\text{dep}_v-2\times \text{dep}_k,h_u+h_v+x\}

如果当前的答案为 ansansd(u,v)d(u,v) 只有 depu+depv2×depk>ans\text{dep}_u+\text{dep}_v-2\times \text{dep}_k>anshu+hv+x>ansh_u+h_v+x>ansansans 才可被更新。

Mi,jM_{i,j} 表示 ii 子树里面 hx=jh_{x}=j 的最大的 depx\text{dep}_x

由于 ii 的子树里面不可能 dd 全都大于 did_i,因为一定有 00,并且相邻的两个点 dd 值相差不超过 11,所以 0di0\sim d_i 都会在 ii 的子树里面出现,那么 Mi,jMi,j+1M_{i,j}\geq M_{i,j+1}

然后对于 kk 的两个个儿子 aabb,它们子树里如果存在能让 ansans 更新的点对,说明存在 i,ji,j,使得 i+j+x>ansi+j+x>ansMa,i+Mb,j2×depk>ansM_{a,i}+M_{b,j}-2\times\text{dep}_k>ans

移项就得出 Ma,i+Mb,max(ansxi+1,0)2×depk>ansM_{a,i}+M_{b,\max(ans-x-i+1,0)}-2\times \text{dep}_k>ans

容易发现 Mi,jM_{i,j} 不为 00 说明 jj 不超过 ii 这个子树里面的长链长度,所以直接长剖优化即可。

时间复杂度:O(nq)O(nq),常数很大。

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
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e6 + 5;

int n, ans, x;
int d[kMaxN], dep[kMaxN];
std::vector<int> G[kMaxN], f[kMaxN];

void dfs1(int u, int fa) {
dep[u] = dep[fa] + 1;
if (G[u].size() != 1) d[u] = 1e9;
for (auto v : G[u]) {
if (v == fa) continue;
dfs1(v, u);
d[u] = std::min(d[u], d[v] + 1);
}
}

void dfs2(int u, int fa) {
for (auto v : G[u]) {
if (v == fa) continue;
d[v] = std::min(d[v], d[u] + 1);
dfs2(v, u);
}
}

void merge(int u, int v) {
for (int i = 0; i < static_cast<int>(f[v].size()); ++i) {
for (;;) {
int j = std::max(ans - x - i + 1, 0);
if (j < static_cast<int>(f[u].size()) && f[v][i] + f[u][j] - 2 * dep[u] > ans) ++ans;
else break;
}
}
for (int i = 0; i < static_cast<int>(f[v].size()); ++i)
f[u][i] = std::max(f[u][i], f[v][i]);
}

void dfs3(int u, int fa) {
int mxid = 0;
for (auto v : G[u]) {
if (v == fa) continue;
dfs3(v, u);
if (f[v].size() > f[mxid].size()) mxid = v;
}
std::swap(f[u], f[mxid]);
for (auto v : G[u]) {
if (v == fa || v == mxid) continue;
merge(u, v);
}
for (;;) {
int i = std::max(ans - x - d[u] + 1, 0);
if (i < static_cast<int>(f[u].size()) && f[u][i] - dep[u] > ans) ++ans;
else break;
}
if (d[u] == static_cast<int>(f[u].size()))
f[u].emplace_back(dep[u]);
}

void dickdreamer() {
std::cin >> n;
for (int i = 2; i <= n; ++i) {
int p;
std::cin >> p;
G[p].emplace_back(i), G[i].emplace_back(p);
}
dfs1(1, 0), dfs2(1, 0);
int q;
std::cin >> q;
for (; q; --q) {
std::cin >> x;
for (int i = 1; i <= n; ++i) {
f[i].clear(), f[i].shrink_to_fit();
}
ans = 0;
dfs3(1, 0);
std::cout << ans << ' ';
}
}

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

CF1712F Triameter 题解
https://sobaliuziao.github.io/2023/08/31/post/a479195a.html
作者
Egg_laying_master
发布于
2023年8月31日
许可协议