P11364 题解
这是一篇两只
发现区间更大一定不优,所以本质上是在求
首先考虑 A 性质,此时区间 LCA 等于区间深度最小值。注意到这是经典的最小值最大问题,考虑二分答案
考场上的我止步于此。
这时需要注意到一个结论:
令
a_i=\text{dep}_{\text{LCA}(i, i+1)} ,那么对于l<r 有\text{dep}_{\text{LCA*}(l, r)}=\min\limits_{i=l}^{r-1}a_i 。
简短的证明:
- 因为区间更大一定不优,所以如果将
[l,r] 看作某个[i,i+1] 区间的扩展的话,就可以得到\text{dep}_{\text{LCA*}(l, r)}\le\min\limits_{i=l}^{r-1}a_i 。 - 设
\text{LCA*}(l, r)=x ,那么一定存在一对点i,j(i<j) 满足i 和j 分别在x 的不同子树中。此时一定存在p\in[i,j) 满足p,p+1 在x 的不同子树中,那么此时a_p 取到\text{dep}_{\text{LCA*}(l, r)} 。
这个时候只需要把之前维护的
时间复杂度
代码:
#include <bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define MAXK 19
int n, q;
int fa[MAXN], siz[MAXN], son[MAXN], top[MAXN], dep[MAXN], rt[MAXN], a[MAXN], id[MAXN]; int f[MAXN][MAXK];
vector<int> e[MAXN], vec[MAXN];
void dfs1(int x, int f){
dep[x] = dep[fa[x]=f]+(siz[x]=1);
for (auto i: e[x]) if (i ^ f){
dfs1(i, x); siz[x] += siz[i]; if (siz[i] > siz[son[x]]) son[x] = i;
}
}
void dfs2(int x, int tp){
top[x] = tp; if (son[x]) dfs2(son[x], tp); for (auto i: e[x]) if (i != son[x] && i != fa[x]) dfs2(i, i);
}
int LCA(int x, int y){
for (; top[x]^top[y]; x=fa[top[x]]) if (dep[top[x]] < dep[top[y]]) swap(x, y); return dep[x] < dep[y] ? x : y;
}
int qry(int l, int r){int k(__lg(r-l+1)); return max(f[l][k], f[r-(1<<k)+1][k]);}
namespace Seg{
int ct; struct Node{int lmx, rmx, ans, s;}; struct T{Node p; int ls, rs;}tr[MAXN<<5];
Node merge(Node a, Node b){
return {a.lmx == a.s ? a.s+b.lmx : a.lmx, b.rmx == b.s ? b.s+a.rmx : b.rmx,
max({a.ans, b.ans, a.rmx+b.lmx}), a.s+b.s};
}
void push_up(int p){tr[p].p = merge(tr[tr[p].ls].p, tr[tr[p].rs].p);}
void build(int &p, int l, int r){
p = ++ct; if (l == r){tr[p].p = {0, 0, 0, 1}; return;} int mid((l+r)>>1);
build(tr[p].ls, l, mid); build(tr[p].rs, mid+1, r); push_up(p);
}
void modify(int &p, int l, int r, int x){
tr[++ct] = tr[p]; p = ct; if (l == r){tr[p] = {1, 1, 1, 1}; return;} int mid((l+r)>>1);
if (x <= mid) modify(tr[p].ls, l, mid, x); else modify(tr[p].rs, mid+1, r, x); push_up(p);
}
Node qry(int p, int l, int r, int L, int R){
if (L <= l && r <= R) return tr[p].p; int mid((l+r)>>1); Node res = {0, 0, 0, 0};
if (L <= mid) res = merge(res, qry(tr[p].ls, l, mid, L, R));
if (R > mid) res = merge(res, qry(tr[p].rs, mid+1, r, L, R)); return res;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n; for (int i(1), u, v; i<n; ++i) cin >> u >> v, e[u].push_back(v), e[v].push_back(u); dfs1(1, 0); dfs2(1, 1);
for (int i(1); i<=n; ++i) f[i][0] = dep[i]; for (int i(1); i<n; ++i) a[i] = dep[LCA(i, i+1)];
for (int j(1); j<MAXK; ++j) for (int i(1); i+(1<<j)-1<=n; ++i) f[i][j] = max(f[i][j-1], f[i+(1<<(j-1))][j-1]);
iota(id+1, id+n, 1); sort(id+1, id+n, [](int x, int y){return a[x] < a[y];});
Seg::build(rt[n], 1, n); for (int i(n-1); i; --i) Seg::modify(rt[i]=rt[i+1], 1, n, id[i]);
cin >> q;
for (int x, y, k; q; --q){
cin >> x >> y >> k; if (k == 1){cout << qry(x, y) << '\n'; continue;}
int l(1), r(n-1), mid;
while (l < r){
mid = (l+r+1) >> 1; if (Seg::qry(rt[mid], 1, n, x, y-1).ans >= k-1) l = mid; else r = mid-1;
}
cout << a[id[l]] << '\n';
}
return 0;
}