类似 QTREE 的套路, 我们维护到Splay最浅点的最长路径Lmax, 最深点的最长路径Rmax
考虑如何Pushup?
son 是虚子树, 用一个 multiset 维护虚子树
#include<bits/stdc++.h>
#define N 200050
using namespace std;
typedef long long ll;
const ll inf = 100000000000000;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
int n, m, first[N], nxt[N], to[N], tot;
void add(int x, int y){nxt[++tot] = first[x], first[x]=tot, to[tot] = y;}
ll val[N], sum[N], Lmax[N], Rmax[N]; int ch[N][2], fa[N];
multiset<ll> S[N];
#define ls ch[x][0]
#define rs ch[x][1]
bool isRoot(int x){ return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
ll Top(int x){ if(!S[x].empty()) return *S[x].rbegin(); return - inf;}
void Pushup(int x){ if(!x) return;
sum[x] = sum[ls] + sum[rs] + val[x];
Lmax[x] = max(Lmax[ls], sum[ls] + max(val[x], (max(Lmax[rs], Top(x)) + val[x])));
Rmax[x] = max(Rmax[rs], sum[rs] + max(val[x], (max(Rmax[ls], Top(x)) + val[x])));
}
void rotate(int x){
int y = fa[x], z = fa[y], k = ch[y][1] == x;
if(!isRoot(y)) ch[z][ch[z][1] == y] = x; fa[x] = z;
ch[y][k] = ch[x][k^1]; fa[ch[x][k^1]] = y;
ch[x][k^1] = y; fa[y] = x; Pushup(y); Pushup(x);
}
void Splay(int x){
while(!isRoot(x)){
int y = fa[x], z = fa[y];
if(!isRoot(y)) rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y); rotate(x);
} Pushup(x);
}
void Access(int x){
for(int y = 0; x; y = x, x = fa[x]){
Splay(x);
if(rs) S[x].insert(Lmax[rs]);
rs = y;
if(rs) S[x].erase(Lmax[rs]);
Pushup(x);
}
}
int main(){
n = read(), m = read();
Lmax[0] = Rmax[0] = - inf;
for(int i=2; i<=n; i++) fa[i] = read();
for(int i=1; i<=n; i++) val[i] = read();
for(int i=n; i>=1; i--) Pushup(i), S[fa[i]].insert(Lmax[i]);
while(m--){
int op = read();
if(op == 1){
int x = read(); Access(x); Splay(x); printf("%lld\n", Rmax[x]);
}
if(op == 2){
int x = read(), v = read();
Access(x); Splay(x); val[x] = v; Pushup(x);
}
} return 0;
}