不要脸的安利自己的博客
Link
主要说一下那种线段树的做法吧。(跑的贼快
首先看到这种子树的问题,直接 dfs 序先跑下来。这样的话其实就是相当于求一个区间内部的最大值。和区间修改。形式化的来说。要求支持一下两个操作。
- 将子树 x 内部的点的 ai 值全部加 x。
- 求子树 x 内部的 biΔ+ai×bi 的最大值。
那么这样的操作可以想到利用线段树去维护。对于每一个点,我们可以把这个点看成一条线段。即 bix+ai×bi,那么其实就是维护一个凸壳,但是考虑一下维护凸壳的过程,其实是对于一条直线来说,找到最早的与他相交的点。于是乎我们可以利用线段树去维护这个交点的横坐标和区间的最大值的那一条线段是什么。那么在修改的时候呢?主要利用的是吉司机线段树的思想。如果说当前我加的权值不够达到最小的相交的那个点(也就是发生最大值改变的那个点)的话。那么我们可以直接打上懒标记,也就是把相交的点向左移动,在 pushup
的时候进行更新答案。否则的话直接递归进子树。
由于是带着绝对值的,所以我们另外进行维护一个负的权值的即可。
时间复杂度是 O(nlog3),但是实际上效率很高,代码也不是很难写。(至少比分块好写多了)
#include<bits/stdc++.h>
#define g() getchar()
#define il inline
#define ull unsigned long long
#define eps 1e-10
#define ll long long
#define pa pair<int, int>
#define for_1(i, n) for(int i = 1; i <= (n); ++i)
#define for_0(i, n) for(int i = 0; i < (n); ++i)
#define for_xy(i, x, y) for(int i = (x); i <= (y); ++i)
#define for_yx(i, y, x) for(int i = (y); i >= (x); --i)
#define for_edge(i, x) for(int i = head[x]; i; i = nxt[i])
#define int long long
#define DB double
#define ls (p<<1)
#define rs (p<<1|1)
#define m_p make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 10, INF = 1e18, mod = 1e9 + 7;
il int qpow(int x, int k) {int ans = 1; while(k) {if(k & 1) ans = ans * x % mod; x = x * x % mod; k >>= 1; } return ans; }
il int Add(int x, int y) {return (x += y) %= mod;}
il int Del(int x, int y) {return (x = x - y + mod) % mod;}
il int Mul(int x, int y) {return x * y % mod;}
il int inv(int x) {return qpow(x, mod - 2); }
inline int re() {
int x = 0, p = 1;
char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();}
while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * p;
}
int head[N], ver[N], nxt[N], tot;
il void add(int x, int y) {ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot; }
int n, q, cnt;
int fa[N], a[N], w[N], dfn[N], ed[N];
void dfs(int x) {dfn[x] = ++cnt; for_edge(i, x)dfs(ver[i]); ed[x] = cnt; }
struct Seg {
int a[N], b[N], lz[N], Fk[N];
struct Line{int k, b; } mx[N];
pair<Line, int> Max(Line a, Line b) {if(a.b < b.b) swap(a, b); return m_p(a, b.k > a.k ? (a.b - b.b) / (b.k - a.k) : INF); }
il void push_up(int p) { pair<Line, int> tmp = Max(mx[ls], mx[rs]); Fk[p] = min(min(Fk[ls], Fk[rs]), tmp.second); mx[p] = tmp.first; }
void Build(int p, int l, int r) {
lz[p] = 0; Fk[p] = INF; if(l == r) {mx[p] = Line{b[l], a[l] * b[l]}; return; }
int mid = (l + r) >> 1; Build(ls, l, mid); Build(rs, mid + 1, r); push_up(p);
}
il void push_down(int p) {
mx[ls].b += mx[ls].k * lz[p]; mx[rs].b += mx[rs].k * lz[p];
Fk[ls] -= lz[p]; Fk[rs] -= lz[p]; lz[ls] += lz[p]; lz[rs] += lz[p]; lz[p] = 0; return;
}
void Update(int p, int L, int R, int l, int r, int v) {
int mid = (L + R) >> 1;
if(l <= L and r >= R) {
if(v > Fk[p]) { push_down(p); Update(ls, L, mid, l, r, v); Update(rs, mid + 1, R, l, r, v); push_up(p); }
else Fk[p] -= v, lz[p] += v, mx[p].b += mx[p].k * v; return ;
}
push_down(p); if(l <= mid) Update(ls, L, mid, l, r, v); if(r > mid) Update(rs, mid + 1, R, l, r, v); push_up(p);
}
int Query(int p, int L, int R, int l, int r) {
if(l <= L and r >= R) return mx[p].b; push_down(p); int mid = (L + R) >> 1, res = -INF;
if(l <= mid) res = max(res, Query(ls, L, mid, l, r)); if(r > mid) res = max(res, Query(rs, mid + 1, R, l, r)); return res;
}
}A, B;
signed main() {
n = re(), q = re(); for(int i = 2; i <= n; ++i) fa[i] = re(), add(fa[i], i); for_1(i, n) a[i] = re(), a[i] += a[fa[i]]; for_1(i, n) w[i] = re(), w[i] += w[fa[i]];
dfs(1); for(int i = 1; i <= n; ++i) A.b[dfn[i]] = w[i], B.b[dfn[i]] = -w[i], A.a[dfn[i]] = B.a[dfn[i]] = a[i]; A.Build(1, 1, n); B.Build(1, 1, n);
while(q--) {
int op = re(); int x = re();
if(op == 1) {int v = re(); A.Update(1, 1, n, dfn[x], ed[x], v); B.Update(1, 1, n, dfn[x], ed[x], v); }
else printf("%lld\n", max(A.Query(1, 1, n, dfn[x], ed[x]), B.Query(1, 1, n, dfn[x], ed[x])));
}
}
__EOF__
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析