[SCOI2018] Tree [LCT]

传送门

类似 QTREE 的套路, 我们维护到Splay最浅点的最长路径Lmax, 最深点的最长路径Rmax

考虑如何Pushup? Lmax(x)=max(Lmax(ls), val[x], val[x]+max(Lmax(rs), Max(son)))

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值