tianyu_awa
2024-11-16 21:39:33
题目上的式子很难维护,可以转换成
定义
把tag加上,再把绝对值拆开,中间的式子就变成了
中间的这两个本质上是直线,可以用李超线段树维护,区间加可以用分块。
code:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5+5;
namespace tianyu{
const int W = 1e9;
int n;
vector<int> G[N];
int fa[N], dfn[N], rnk[N], tot1;
ll a[N];
int b[N];
int end[N];
void dfs(int u, int f){
rnk[dfn[u] = ++tot1] = u;
for (int v : G[u]){
if (v == f) continue;
a[v] += a[u];
b[v] += b[u];
dfs(v, u);
}
b[u] = abs(b[u]);
end[u] = tot1;
}
struct node{
int ls, rs;
ll a, b;
node() : ls(0), rs(0) {}
}tr[3200005];
int tot;
int root[505];
#define calc(a, b, x) (abs(a + x) * b)
#define calc1(a, b, x) ((a + x) * b)
#define cmp(x) (calc1(a, b, x) > calc1(tr[p].a, tr[p].b, x))
void insert(int &p, int l, int r, ll a, ll b){
if (!p){
p = ++tot;
tr[p].a = a, tr[p].b = b;
return;
}int mid = (l + r) >> 1;
if (cmp(mid)) swap(tr[p].a, a), swap(tr[p].b, b);
if (cmp(l)) insert(tr[p].ls, l, mid, a, b);
if (cmp(r)) insert(tr[p].rs, mid + 1, r, a, b);
}
ll query(int p, int l, int r, int x){
if (!p) return -1145141919810;
ll res = calc1(tr[p].a, tr[p].b, x);
if (l == r) return res;
int mid = (l + r) >> 1;
if (x <= mid) return max(res, query(tr[p].ls, l, mid, x));
else return max(res, query(tr[p].rs, mid + 1, r, x));
}
int bel[N];
int bl[505], br[505], tag[505];
inline void ins(int i){
insert(root[bel[i]], 0, W, a[rnk[i]], b[rnk[i]]);
insert(root[bel[i]], 0, W, a[rnk[i]], -b[rnk[i]]);
}
inline void rebuild(int bid){
root[bid] = 0;
for (int i = bl[bid];i <= br[bid];i++){
a[rnk[i]] += tag[bid];
ins(i);
}
tag[bid] = 0;
}
void add(int l, int r, int k){
int L = bel[l], R = bel[r];
if (L == R){
for (int i = l;i <= r;i++){
a[rnk[i]] += k;
}
rebuild(L);
return;
}
if (l != bl[L]){
for (int i = l;i <= br[L];i++){
a[rnk[i]] += k;
}rebuild(L);
++L;
}
if (r != br[R]){
for (int i = r;i >= bl[R];i--){
a[rnk[i]] += k;
}rebuild(R);
--R;
}
for (int i = L;i <= R;i++){
tag[i] += k;
}
}
ll query(int l, int r){
int L = bel[l], R = bel[r];
ll res = -1145141919810;
if (L == R){
for (int i = l;i <= r;i++){
res = max(res, calc(a[rnk[i]], b[rnk[i]], tag[L]));
}return res;
}
for (int i = l;i <= br[L];i++){
res = max(res, calc(a[rnk[i]], b[rnk[i]], tag[L]));
}
for (int i = r;i >= bl[R];i--){
res = max(res, calc(a[rnk[i]], b[rnk[i]], tag[R]));
}
for (int i = L + 1;i < R;i++){
res = max(res, query(root[i], 0, W, tag[i]));
}
return res;
}
int q;
void awa(){
cin >> n >> q;
for (int i = 2;i <= n;i++){cin >> fa[i];G[fa[i]].emplace_back(i);}
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 1;i <= n;i++) cin >> b[i];
dfs(1, 0);
int len = 600;
for (int i = 1;i <= n;i++){
bel[i] = (i - 1) / len + 1;
if (!bl[bel[i]]) bl[bel[i]] = i;
br[bel[i]] = i;
ins(i);
}
while (q--){
int op, x, k;
cin >> op >> x;
if (op == 1){
cin >> k;
if (!k) continue;
add(dfn[x], end[x], k);
}
else{
cout << query(dfn[x], end[x]) << '\n';
}
}
}
}
signed main(){
int T = 1;
while (T--) tianyu::awa();
return 0;
}