「Ynoi2004」rpmtdq
带权无根树,每次查询 \(\min\limits_{l \leq i < j \leq r} {dis(i, j)}\),\(1 \leq n \leq 2 \times 10^5, 1 \leq q \leq 10^6\)。
区间所有点对最小值,考虑历史版本和、支配对等等,这道题使用支配对,但直接做没头绪,联系查询距离相关,所以考虑点分治,在操作以 \(u\) 为根子树时,由于区间取最小值,所以我们可以直接将 \(dis(u, i) + dis(u, j)\) 当成此时 \(dis(i, j)\),可以证明不影响答案,把某点到 \(u\) 的距离作为其权值 \(a\),然后拿出整棵子树结点并按编号排序,容易观察到此时若有 \(i < j < k\) 且 \(a_j > \max(a_i, a_k)\) 则点对 \((i, k)\) 无效,因为由 \(\min(a_i, a_k)\) 对应那个点与 \(j\) 组成的点对构成区间更小,权值更小,支配了 \((i, k)\),然后思考点对数量,发现若 \(u\) 子树大小为 \(O(S)\) 的,则点对数量也是 \(O(S)\) 的,所以总的点对数量是 \(O(N \log N)\) 的(证明留给读者思考)。
然后找支配对,其实把上面无效条件写出来后就比较好想了,反过来点对 \((i, j)\) 有效的条件就是 \(\min\limits_{i < u < j} a_u > \max(a_i, a_j)\),这个正反两遍单调栈就做完了(也变相证明了点对数量上限)。
查询答案扫描线即可。
/*
address:https://www.luogu.com.cn/problem/P9058
AC 2026/9/17 12:42
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, LL> pil;
typedef pair<int, int> pii;
#define mkp make_pair
const int N = 2e5 + 5, Q = 1e6 + 5;
const LL INF = 1e18;
struct edge { int to, w; };
vector<edge>G[N];
int n, q;
inline void read(int& x) {
x = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
int siz[N];
bool vis[N];
inline int find(int u, int fa, int n) {
siz[u] = 1;
bool half = true;
for (auto [v, w] : G[u])
if (v != fa && !vis[v]) {
int ret = find(v, u, n);
if (ret) return ret;
half &= siz[v] <= n >> 1;
siz[u] += siz[v];
}
if (half && n - siz[u] <= n >> 1) return u;
return 0;
}
inline int get_siz(int u, int fa) {
int ret = 1;
for (auto [v, w] : G[u])
if (v != fa && !vis[v]) ret += get_siz(v, u);
return ret;
}
LL a[N];
vector<int>node;
inline void assign(int u, int fa) {
node.push_back(u);
for (auto [v, w] : G[u])
if (v != fa && !vis[v]) {
a[v] = a[u] + w;
assign(v, u);
}
}
vector<pil>vec[N];
int stk[N], top;
inline void dfs(int u, int fa) {
node.clear();
int s = get_siz(u, fa);
u = find(u, fa, s);
vis[u] = true;
a[u] = 0;
assign(u, fa);
sort(node.begin(), node.end());
top = 0;
for (int v : node) {
while (top > 0 && a[v] < a[stk[top]]) --top;
if (top) vec[max(v, stk[top])].push_back(mkp(min(v, stk[top]), a[v] + a[stk[top]]));
stk[++top] = v;
}
top = 0;
reverse(node.begin(), node.end());
for (int v : node) {
while (top > 0 && a[v] < a[stk[top]]) --top;
if (top) vec[max(v, stk[top])].push_back(mkp(min(v, stk[top]), a[v] + a[stk[top]]));
stk[++top] = v;
}
for (auto [v, w] : G[u])
if (v != fa && !vis[v]) dfs(v, u);
}
vector<pii>qry[N];
inline void trans(LL& x, LL y) { x = x > y ? y : x; }
struct FenwickTree {
#define lowbit(x) (x & -x)
LL c[N];
inline void init(int n) { fill(c, c + n + 1, INF); }
inline void change(int x, LL k) { for (;x <= n;x += lowbit(x)) trans(c[x], k); }
inline LL query(int x) {
LL ret = INF;
for (;x > 0;x -= lowbit(x)) trans(ret, c[x]);
return ret;
}
}BIT;
LL ans[Q];
int main() {
read(n);
for (int i = 1;i < n;++i) {
int u, v, w;read(u), read(v), read(w);
G[u].push_back({ v, w });
G[v].push_back({ u, w });
}
dfs(1, 0);
read(q);
for (int i = 1, l, r;i <= q;++i) {
read(l), read(r);
ans[i] = -1;
if (l < r) qry[r].push_back(mkp(l, i));
}
BIT.init(n);
for (int i = 1;i <= n;++i) {
for (auto [j, d] : vec[i]) BIT.change(n - j + 1, d);
for (auto [l, id] : qry[i]) ans[id] = BIT.query(n - l + 1);
}
for (int i = 1;i <= q;++i) printf("%lld\n", ans[i]);
return 0;
}

浙公网安备 33010602011771号