CF1192B Dynamic Diameter 题解
思路#
静态
定义#
我们使用簇来表示树上的一个连通块。
可以按照如下方式定义一个簇:
- 一个簇可以表示为三元组
,其中 为树的节点,称为簇的界点, 为一个边的集合,表示该簇包含的边,路径 称作簇路径。 分别为上界点与下界点,上界点是一个簇内深度最小的点,下界点则是除去上界点外的界点。- 界点可以通俗的理解为簇与簇的分界点。
- 对于树的一条边
, 是一个簇。 - 对于簇
与簇 且 ,那么 也是一个簇,这个操作称为 。 - 对于簇
与簇 且 ,那么 (或者 )也是一个簇,这个操作称为 。
经典图:
一个感性理解是
这两个操作可以帮助我们将整棵树合并为一个簇。
- 对于一度点,进行
- 对于二度点,进行
。
收缩过程中,簇的合并结构形成了一个树,我们把这个树称为
现在,这样一个
更优的树#
考虑构造一个树高更小的
容易想到的是全局平衡二叉树。
全局平衡二叉树提供了一个分治方案使整棵树的全局平衡二叉树树高为
我们同样可以把这个分治方案放在
具体的,将树进行重链剖分。
然后对于轻儿子,先把它们
再对重链分治
这样就可以建出一颗树高为
关于这道题#
建出
我们想线段树一样的操作它
对于动态直径。
我们把每一个簇,维护三个值。
簇内部的最长距离及到两个界点的最长距离。
合并时我们对两种操作分类讨论拼接起来即可。
可以发现,维护直径的方式与线段树维护最大子段和的方式是比较类似的。
这种维护方法就可以支持一些简单的修改,比如此题的修改边权。
时间复杂度:
Code#
/*
! 如果没有天赋,那就一直重复
! Created: 2024/06/05 19:58:38
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
const int N = 2e5 + 10;
int n, q, w, ct, last, head[N];
int sz[N], sn[N], fa[N], rt[N], dep[N];
struct Node {
int u, v, w;
} d[N];
struct edge {
int to, nxt;
} e[N << 1];
struct node {
enum { UNIT, RAKE, COMP } type;
int u, v, sz, ls, rs, fa, ln, mi, un, vn;
} t[N << 1];
inline void add(int x, int y) {
e[++ct] = {y, head[x]}, head[x] = ct;
e[++ct] = {x, head[y]}, head[y] = ct;
}
inline void dfs(int now, int fa) {
sz[now] = 1, dep[now] = dep[fa] + 1;
for (int i = head[now]; i; i = e[i].nxt) {
int x = e[i].to;
if (x == fa) continue;
dfs(x, now);
t[x] = {node::UNIT, now, x, 1};
sz[now] += sz[x];
if (sz[x] > sz[sn[now]]) sn[now] = x;
}
}
inline void pup(int p) {
int x = t[p].ls, y = t[p].rs;
if (t[p].type == node::RAKE) {
t[p].ln = t[x].ln;
t[p].mi = max({t[x].mi, t[y].mi, t[x].un + t[y].un});
t[p].un = max(t[x].un, t[y].un);
t[p].vn = max(t[x].vn, t[x].ln + t[y].un);
} else if (t[p].type == node::COMP) {
t[p].ln = t[x].ln + t[y].ln;
t[p].mi = max({t[x].mi, t[y].mi, t[x].vn + t[y].un});
t[p].un = max(t[x].un, t[x].ln + t[y].un);
t[p].vn = max(t[y].vn, t[y].ln + t[x].vn);
}
}
inline auto rake(int x, int y) {
assert(t[x].u == t[y].u);
return t[++ct] = {node::RAKE, t[x].u, t[x].v, t[x].sz + t[y].sz, x, y}, t[x].fa = t[y].fa = ct, pup(ct), ct;
}
inline auto comp(int x, int y) {
assert(t[x].v == t[y].u);
return t[++ct] = {node::COMP, t[x].u, t[y].v, t[x].sz + t[y].sz, x, y}, t[x].fa = t[y].fa = ct, pup(ct), ct;
}
template<typename T, typename Func>
inline int build(T l, T r, Func f) {
if (r == l) return 0;
if (r == l + 1) return *l;
int all = 0, sum = 0;
for (auto it = l; it != r; it++) all += t[*it].sz;
T mid = l + 1;
for (auto it = l; it != r; it++) {
sum += t[*it].sz;
if (sum <= all / 2) mid = it + 1; else break;
}
return f(build(l, mid, f), build(mid, r, f));
}
inline void sol(int now, int ff, bool f) {
fa[now] = ff;
if (sn[now]) sol(sn[now], now, false);
for (int i = head[now]; i; i = e[i].nxt)
if (e[i].to != sn[now] && e[i].to != fa[now]) sol(e[i].to, now, true);
if (f) {
vector<int> s1;
if (ff) s1.push_back(now);
for (int i = sn[now]; i; i = sn[i]) {
vector<int> s2{i};
for (int j = head[fa[i]]; j; j = e[j].nxt)
if (e[j].to != i && e[j].to != fa[fa[i]]) s2.push_back(rt[e[j].to]);
s1.push_back(build(s2.begin(), s2.end(), rake));
}
rt[now] = build(s1.begin(), s1.end(), comp);
}
}
inline void upd(int x, int w) {
t[x].un = t[x].vn = t[x].mi = t[x].ln = w;
while (t[x].fa) {
pup(t[x].fa), x = t[x].fa;
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q >> w;
fro(i, 1, n - 1) {
cin >> d[i].u >> d[i].v >> d[i].w;
add(d[i].u, d[i].v);
}
ct = n;
dfs(1, 0);
sol(1, 0, 1);
fro(i, 1, n - 1) {
if (dep[d[i].u] > dep[d[i].v])
swap(d[i].u, d[i].v);
upd(d[i].v, d[i].w);
}
fro(i, 1, q) {
int x, y;
cin >> x >> y;
x = (x + last) % (n - 1) + 1;
y = (y + last) % (w);
d[x].w = y;
upd(d[x].v, d[x].w);
cout << (last = t[rt[1]].mi) << "\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)