题解 P5654 【基础函数练习题】
题意简述:
题目说得很清楚了。
题解:
观察这个函数,
很显然,当询问
考虑询问
上图为序列
当询问
首先有区间的笛卡尔树的根节点应该是这两个点在原笛卡尔树上的 LCA,只不过在这个例子中恰好是根。
可以发现点
也就是说,区间
令
以左侧的
考虑使用倍增,从
注意:这里说的祖先都是不断通过红色边上升到达的点,而不是原笛卡尔树的祖先。
红色边:
首先预处理
上述预处理不难合并,具体可以看代码。
查询的时候也是同理,从
对
总结:不需要用到任何数据结构,仅需掌握笛卡尔树和倍增的知识点,实乃小清新树上问题(大雾)
总结:注意卡空间,因为倍增的空间消耗很大,而且很多数组要开 long long 类型,不得不合并一些预处理数组,而且还需左右两边分开处理,不占用重复空间才卡过去。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define _L_ 0
#define _R_ 1
int lr;
typedef long long LL;
const int MN = 500005, MQ = 500005;
int N, Q, root, A[MN], V[MN];
int dep[MN], lc[MN], rc[MN], faz[MN][19];
LL S[MN], _chain[MN][19], _subt[MN][19];
void DFS0(int u) {
for (int j = 0; j < 18 && faz[u][j]; ++j) faz[u][j + 1] = faz[faz[u][j]][j];
if (lc[u]) dep[lc[u]] = dep[u] + 1, DFS0(lc[u]);
if (rc[u]) dep[rc[u]] = dep[u] + 1, DFS0(rc[u]);
S[u] = std::max(S[lc[u]], S[rc[u]]) + V[u];
}
void Init() {
static int stk[MN]; int tp = 0, x;
for (int i = 1; i <= N; ++i) {
x = 0;
while (tp && A[stk[tp]] < A[i]) {
if (x) rc[stk[tp]] = x, faz[x][0] = stk[tp];
x = stk[tp], --tp;
}
if (x) lc[i] = x, faz[x][0] = i;
stk[++tp] = i;
}
x = 0;
while (tp) {
if (x) rc[stk[tp]] = x, faz[x][0] = stk[tp];
x = stk[tp], --tp;
}
dep[x] = 1, DFS0(x);
root = x;
}
inline int lca(int u, int v) {
if (dep[u] < dep[v]) std::swap(u, v);
for (int d = dep[u] - dep[v], j = 0; d; d >>= 1, ++j)
if (d & 1) u = faz[u][j];
if (u == v) return u;
for (int j = 18; j >= 0; --j)
if (faz[u][j] != faz[v][j])
u = faz[u][j],
v = faz[v][j];
return faz[u][0];
}
void DFS1(int u) {
_chain[u][0] = V[u];
if (lr == _L_) _subt[u][0] = S[lc[u]] + V[u];
if (lr == _R_) _subt[u][0] = S[rc[u]] + V[u];
for (int j = 0; j < 18; ++j) {
faz[u][j + 1] = faz[faz[u][j]][j];
if (!faz[u][j + 1]) break;
_chain[u][j + 1] = _chain[u][j] + _chain[faz[u][j]][j];
_subt[u][j + 1] = std::max(_chain[faz[u][j]][j] + _subt[u][j], _subt[faz[u][j]][j]);
}
if (lc[u]) {
if (lr == _L_) faz[lc[u]][0] = faz[u][0];
if (lr == _R_) faz[lc[u]][0] = u;
DFS1(lc[u]);
}
if (rc[u]) {
if (lr == _L_) faz[rc[u]][0] = u;
if (lr == _R_) faz[rc[u]][0] = faz[u][0];
DFS1(rc[u]);
}
}
inline LL calc(int u, int z) {
LL val = 0;
for (int j = 18; j >= 0; --j)
if (dep[faz[u][j]] >= dep[z]) {
val = std::max(val + _chain[u][j], _subt[u][j]);
u = faz[u][j];
}
return val;
}
int ql[MQ], qr[MQ], qz[MQ];
LL Ans[MQ];
int main() {
scanf("%d%d", &N, &Q);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
for (int i = 1; i <= N; ++i) scanf("%d", &V[i]);
Init();
for (int i = 1; i <= Q; ++i) {
scanf("%d%d", &ql[i], &qr[i]), qz[i] = lca(ql[i], qr[i]);
Ans[i] = -0x3f3f3f3f3f3f3f3f;
}
memset(faz, 0, sizeof faz), lr = _R_, DFS1(root);
for (int i = 1; i <= Q; ++i) Ans[i] = std::max(Ans[i], calc(ql[i], qz[i]) + V[qz[i]]);
memset(faz, 0, sizeof faz), lr = _L_, DFS1(root);
for (int i = 1; i <= Q; ++i) Ans[i] = std::max(Ans[i], calc(qr[i], qz[i]) + V[qz[i]]);
for (int i = 1; i <= Q; ++i) printf("%lld\n", ql[i] <= qr[i] ? Ans[i] : 0ll);
return 0;
}