NOIP2024 树上查询
考虑树上启发式合并维护所有连续段,不难发现我们可以造出 \(\mathcal O(n\log n)\) 个连续段。
如果观察得比较仔细,对于每个 \(i\),\((i, i + 1)\) 只会在一个点合并一次,每次合并至多产生一个连续段,所以本质不同的连续段个数为 \(\mathcal O(n)\),可以使用并查集。
考虑我们现在有 \(\mathcal O(n)\) 个区间以及权值 \((l_i, r_i, w_i)\),有若干个询问区间 \([l_q, r_q]\),求 \(\max\limits_{[l_i, r_i] \cap [l_q, r_q] \cap \mathbf N \ge k_q} w_i\)。
分成四类:
-
\(l_i \le l_q \le r_i \le r_q\)
-
\(l_q \le l_i \le r_q \le r_i\)
-
\(l_i \le l_q \le r_q \le r_i\)
-
\(l_q \le l_i \le r_i \le r_q\)
第三类直接二维数点,是容易的。
第一类和第四类可以考虑这样做:按 \(r_i - l_i + 1\) 和 \(k_q\) 排序,依次插入。插入 \((l_i, r_i, w_i)\) 时在位置 \(l_i\) chkmax \(w_i\),查询 \([l_q, r_q]\) 时求位置 \(l_q \sim r_q - k_q + 1\) 上的最大值。
第二类同理,不算并查集的话时间复杂度为 \(\mathcal O(n\log n)\)。
- 启示:启发式合并维护连续段;不同形式的二维数点。
点击查看代码
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
namespace Initial {
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb emplace_back
#define i128 __int128
using namespace std;
template <class T>
void rd(T &x) {
char ch; bool f = 0;
while(!isdigit(ch = getchar()))
if(ch == '-') f = 1;
x = ch - '0';
while(isdigit(ch = getchar()))
x = (x << 1) + (x << 3) + ch - '0';
if(f) x = -x;
}
void write(const ll x, const char str[] = "") {
if(x > 9) write(x / 10);
putchar(x % 10 + '0'), printf("%s", str);
}
const ll maxn = 5e5 + 10, inf = 1e18, mod = 1e9 + 7;
ll power(ll a, ll b = mod - 2) {
ll s = 1;
while(b) {
if(b & 1) s = 1ll * s * a %mod;
a = 1ll * a * a %mod, b >>= 1;
} return s;
}
template <class T>
const ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
template <class T>
void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T>
void chkmax(T &x, const T y) { x = x < y? y : x; }
template <class T>
void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;
struct DSU {
ll d[maxn];
ll find(ll x) { return d[x] ^ x? d[x] = find(d[x]) : x; }
void merge(ll x, ll y) { d[find(x)] = find(y); }
} Left, Right;
ll n, siz[maxn], son[maxn], q, ti, dfn[maxn], out[maxn], idfn[maxn];
vector <ll> to[maxn]; ll dep[maxn], mged[maxn];
void dfs1(ll u, ll fa = 0) {
siz[u] = 1, idfn[dfn[u] = ++ti] = u, dep[u] = dep[fa] + 1;
for(ll v: to[u])
if(v ^ fa) {
dfs1(v, u), siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
} out[u] = ti;
}
struct seg { ll l, r, w; } a[maxn << 1]; ll m;
struct qur { ll l, r, k, id; } b[maxn];
vector <ll> ffc;
void add(ll x) {
Left.merge(x, x - 1), Right.merge(x, x + 1);
ll flg = 0;
if(Left.find(x) < x - 1 && !mged[x - 1]) flg = 1, mged[x - 1] = 1;
if(Right.find(x) > x + 1 && !mged[x]) flg = 1, mged[x] = 1;
if(flg) ffc.pb(x);
}
void dfs2(ll u, ll fa = 0) {
for(ll v: to[u])
if(v != fa && v != son[u]) {
dfs2(v, u);
for(ll i = dfn[v], x; i <= out[v]; i++)
x = idfn[i], Left.d[x] = Right.d[x] = x;
}
if(son[u]) dfs2(son[u], u); ffc.clear();
for(ll v: to[u])
if(v != fa && v != son[u])
for(ll i = dfn[v]; i <= out[v]; i++)
add(idfn[i]);
add(u);
for(ll x: ffc) a[++m] = (seg) { Left.find(x) + 1,
Right.find(x) - 1, dep[u] };
}
struct SGT {
ll mx[maxn << 2];
void modify(ll p, ll l, ll r, ll x, ll v) {
chkmax(mx[p], v); if(l == r) return;
ll mid = l + r >> 1;
if(x <= mid) modify(p << 1, l, mid, x, v);
else modify(p << 1|1, mid + 1, r, x, v);
}
ll query(ll p, ll l, ll r, ll ql, ll qr) {
if(ql <= l && r <= qr) return mx[p];
if(r < ql || qr < l) return -inf;
ll mid = l + r >> 1;
return max(query(p << 1, l, mid, ql, qr),
query(p << 1|1, mid + 1, r, ql, qr));
}
} tr; ll ans[maxn], tree[maxn];
void tr_add(ll x, ll v) {
for(; x <= n; x += x & -x) chkmax(tree[x], v);
}
ll tr_ask(ll x) {
ll v = 0;
for(; x; x -= x & -x) chkmax(v, tree[x]);
return v;
}
int main() {
// freopen("query.in", "r", stdin);
// freopen("query.out", "w", stdout);
rd(n);
for(ll i = 0; i <= n + 1; i++) Left.d[i] = Right.d[i] = i;
for(ll i = 1; i < n; i++) {
ll u, v; rd(u), rd(v);
to[u].pb(v), to[v].pb(u);
} dfs1(1);
dfs2(1);
sort(a + 1, a + 1 + m, [](seg a, seg b) {
return a.r - a.l > b.r - b.l;
}); rd(q);
for(ll i = 1; i <= q; i++)
rd(b[i].l), rd(b[i].r), rd(b[b[i].id = i].k);
sort(b + 1, b + 1 + q, [](qur a, qur b) {
return a.k > b.k;
});
for(ll i = 1; i <= n; i++) a[++m] = (seg) { i, i, dep[i] };
for(ll i = 1, j = 1; i <= q; i++) {
while(j <= m && a[j].r - a[j].l + 1 >= b[i].k)
tr.modify(1, 1, n, a[j].l, a[j].w), ++j;
chkmax(ans[b[i].id], tr.query(1, 1, n, b[i].l, b[i].r - b[i].k + 1));
} tr = {};
for(ll i = 1, j = 1; i <= q; i++) {
while(j <= m && a[j].r - a[j].l + 1 >= b[i].k)
tr.modify(1, 1, n, a[j].r, a[j].w), ++j;
chkmax(ans[b[i].id], tr.query(1, 1, n, b[i].l + b[i].k - 1, b[i].r));
}
sort(a + 1, a + 1 + m, [](seg a, seg b) {
return a.r > b.r;
});
sort(b + 1, b + 1 + q, [](qur a, qur b) {
return a.r > b.r;
});
for(ll i = 1, j = 1; i <= q; i++) {
while(j <= m && a[j].r >= b[i].r) tr_add(a[j].l, a[j].w), ++j;
chkmax(ans[b[i].id], tr_ask(b[i].l));
}
for(ll i = 1; i <= q; i++) write(ans[i], "\n");
return 0;
}

浙公网安备 33010602011771号