CF1628E Groceries in Meteor Town 题解
这为啥有 *3100。
考虑询问本质上在干什么。
树上两点之间边权最大值,相当于两点在 Kruskal 重构树(边权从小到大排序)上 LCA 的点权。
设
于是我们要求
通过观察可知,这个东西等于所有白点的 LCA 和
注意到这是个点集 LCA 的问题,只需要把 DFS 序最大和最小的两个点弄出来即可,线段树维护。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
using namespace std;
const int N = 6e5 + 5;
vector<int> G[N];
int val[N];
int n, q;
int nfa[N][21], dep[N];
class Union_Find
{
public:
int idx;
int fa[N];
void Init()
{
for (int i = 0; i < N; i++) fa[i] = i;
idx = n;
}
int find(int u)
{
return (fa[u] == u ? u : fa[u] = find(fa[u]));
}
void merge(int u, int v, int w)
{
if ((u = find(u)) == (v = find(v))) return;
idx++;
val[idx] = w;
G[idx].emplace_back(u), G[idx].emplace_back(v);
fa[u] = fa[v] = idx;
nfa[u][0] = nfa[v][0] = idx;
}
}uf;
struct Edge
{
int u, v, w;
Edge() = default;
Edge(int u, int v, int w)
: u(u), v(v), w(w)
{
}
bool operator==(const Edge& other) const = default;
}p[N];
int dfn[N], idx, rid[N];
void dfs(int u, int f)
{
dep[u] = dep[f] + 1;
dfn[u] = ++idx;
rid[idx] = u;
for (auto& j : G[u]) dfs(j, u);
}
class SegmentTree
{
public:
struct Node
{
int l, r, maxn, minn;
int tag;
int realmax, realmin;
}tr[N << 2];
void pushup(int u)
{
tr[u].maxn = max(tr[u << 1].maxn, tr[u << 1 | 1].maxn);
tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
tr[u].realmax = max(tr[u << 1].realmax, tr[u << 1 | 1].realmax);
tr[u].realmin = min(tr[u << 1].realmin, tr[u << 1 | 1].realmin);
}
void pushdown(int u)
{
if (tr[u].tag == -1) return;
if (tr[u].tag)
{
tr[u << 1].tag = 1;
tr[u << 1 | 1].tag = 1;
tr[u << 1].realmax = 0, tr[u << 1].realmin = N;
tr[u << 1 | 1].realmax = 0, tr[u << 1 | 1].realmin = N;
}
else
{
tr[u << 1].tag = 0;
tr[u << 1 | 1].tag = 0;
tr[u << 1].realmax = tr[u << 1].maxn, tr[u << 1].realmin = tr[u << 1].minn;
tr[u << 1 | 1].realmax = tr[u << 1 | 1].maxn, tr[u << 1 | 1].realmin = tr[u << 1 | 1].minn;
}
tr[u].tag = -1;
}
void build(int u, int l, int r)
{
tr[u] = { l, r, dfn[l], dfn[l], -1, 0, N };
if (l == r) return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void update(int u, int l, int r, int v)
{
if (tr[u].l >= l and tr[u].r <= r)
{
if (!v)
{
tr[u].tag = 0;
tr[u].realmax = tr[u].maxn, tr[u].realmin = tr[u].minn;
}
else
{
tr[u].tag = 1;
tr[u].realmax = 0, tr[u].realmin = N;
}
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);
pushup(u);
}
int qmax(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r) return tr[u].realmax;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1, res = 0;
if (l <= mid) res = qmax(u << 1, l, r);
if (r > mid) res = max(res, qmax(u << 1 | 1, l, r));
return res;
}
int qmin(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r) return tr[u].realmin;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1, res = N;
if (l <= mid) res = qmin(u << 1, l, r);
if (r > mid) res = min(res, qmin(u << 1 | 1, l, r));
return res;
}
}sgt;
int LCA(int u, int v)
{
if (u == v) return u;
if (dep[u] < dep[v]) swap(u, v);
int k = dep[u] - dep[v], c = 0;
while (k)
{
if (k & 1) u = nfa[u][c];
c++;
k >>= 1;
}
if (u == v) return u;
for (int i = 20; i >= 0; i--)
{
if (nfa[u][i] != nfa[v][i])
{
u = nfa[u][i], v = nfa[v][i];
}
}
return nfa[u][0];
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q;
uf.Init();
for (int i = 1; i < n; i++)
{
int u, v, w;
cin >> u >> v >> w;
p[i] = Edge(u, v, w);
}
sort(p + 1, p + n, [&](const Edge& x, const Edge& y) {return x.w < y.w; });
for (int i = 1; i < n; i++) uf.merge(p[i].u, p[i].v, p[i].w);
dfs(2 * n - 1, 2 * n - 1);
sgt.build(1, 1, n);
for (int i = 1; i <= 20; i++)
{
for (int j = 1; j <= 2 * n - 1; j++) nfa[j][i] = nfa[nfa[j][i - 1]][i - 1];
}
while (q--)
{
int op;
cin >> op;
if (op == 1)
{
int l, r;
cin >> l >> r;
sgt.update(1, l, r, 0);
}
else if (op == 2)
{
int l, r;
cin >> l >> r;
sgt.update(1, l, r, 1);
}
else
{
int x;
cin >> x;
int maxid = sgt.qmax(1, 1, n);
int minid = sgt.qmin(1, 1, n);
if (maxid == 0 || minid == N || (maxid == minid && maxid == dfn[x])) cout << "-1\n";
else
{
cout << val[LCA(x, LCA(rid[maxid], rid[minid]))] << "\n";
}
}
}
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现