CF1192B Dynamic Diameter 题解
马上省选了不会欧拉序,来补补。
首先看到动态维护直径比较容易想到的肯定还是 LCT。常见套路是两个连通块合并后的两直径端点必然是原来两个连通块
于是我们容易搞出 LCT 的只加边维护直径的方法,删除可以离线套线段树分治变成
下面提供两个做法。
做法
考虑还是用上面这个套路,令根为
做法
考虑不用上面的合并套路。直径的本质是什么?如果以一个点(比如
考虑欧拉序,即进行深度优先搜索,到达一个点或者从其儿子回溯到这个点,都将其加到序列后面。最终形成一个长度为
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <functional>
#include <cstring>
#include <string>
#include <vector>
#include <array>
#include <queue>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
int n, q;
ll maxw;
ll lastans;
ll dis[N], nd[N];
array<int, N> dep;
vector<pair<int, ll>> G[N];
array<int, N> euler;
array<int, N> U, V;
array<ll, N> W;
int idx;
array<int, N> fir, lst;
class SegmentTree
{
public:
struct Node
{
int l, r;
ll tag, minn, maxn, res;
ll r1, r2;
friend Node operator+(const Node& a, const Node& b)
{
if (a.l == -1) return b;
if (b.l == -1) return a;
Node c;
c.l = a.l, c.r = b.r;
c.tag = 0ll;
c.minn = min(a.minn, b.minn);
c.maxn = max(a.maxn, b.maxn);
c.res = max({ a.res, b.res, a.r2 + b.maxn, a.maxn + b.r1 });
c.r1 = max({ a.r1, b.r1, b.maxn - 2ll * a.minn });
c.r2 = max({ a.r2, b.r2, a.maxn - 2ll * b.minn });
return c;
}
}tr[N << 2];
void pushtag(int u, ll v)
{
tr[u].tag += v;
tr[u].maxn += v;
tr[u].minn += v;
tr[u].r1 -= v;
tr[u].r2 -= v;
}
function<void(int)> pushdown = [&](int u)
{
if (tr[u].tag)
{
pushtag(u << 1, tr[u].tag);
pushtag(u << 1 | 1, tr[u].tag);
tr[u].tag = 0;
}
};
function<void(int, int, int, ll*)> build = [&](int u, int l, int r, ll* v)
{
tr[u] = { l, r, 0ll, v[r], v[r], 0ll, -v[r], -v[r] };
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid, v);
build(u << 1 | 1, mid + 1, r, v);
tr[u] = tr[u << 1] + tr[u << 1 | 1];
};
function<void(int, int, int, ll)> update = [&](int u, int l, int r, ll v)
{
if (tr[u].l >= l and tr[u].r <= r)
{
pushtag(u, v);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) update(u << 1, l, r, v);
if (r > mid) update(u << 1 | 1, l, r, v);
tr[u] = tr[u << 1] + tr[u << 1 | 1];
};
}sgt;
auto main() -> int
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q >> maxw;
for (int i = 1; i < n; i++)
{
int u, v;
ll w;
cin >> u >> v >> w;
G[u].emplace_back(make_pair(v, w));
G[v].emplace_back(make_pair(u, w));
U[i] = u, V[i] = v, W[i] = w;
}
auto dfs = [&](auto self, int u, int fa) -> void
{
euler[++idx] = u;
if (!fir[u]) fir[u] = idx;
lst[u] = idx;
dep[u] = dep[fa] + 1;
for (auto& [j, w] : G[u])
{
if (j != fa) [[likely]]
{
dis[j] = dis[u] + w;
self(self, j, u);
euler[++idx] = u;
lst[u] = idx;
}
}
};
dfs(dfs, 1, 1);
for (int i = 1; i <= 2 * n - 1; i++)
{
nd[i] = dis[euler[i]];
}
sgt.build(1, 1, 2 * n - 1, nd);
for (int i = 1; i <= q; i++)
{
ll d, e;
cin >> d >> e;
d = (d + lastans) % (n - 1);
e = (e + lastans) % maxw;
d++;
int u = (dep[U[d]] < dep[V[d]] ? V[d] : U[d]);
sgt.update(1, fir[u], lst[u], -W[d] + e);
W[d] = e;
cout << (lastans = sgt.tr[1].res) << "\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!