problem
在大小为 n n n 的树上,点从 1 1 1 到 n n n 标号,第 i i i 个点有权值 a i a_i ai,现在需要支持两种操作:
- 1 U:询问从 U 出发的所有简单路径中,经过的点权值之和的最大值;
- 2 U V:将 U 的权值修改为 V。
注意空间限制 64M。
数据范围: 1 ≤ n ≤ 1 0 5 1\le n\le10^5 1≤n≤105, 1 ≤ m ≤ 1 0 5 1\le m\le10^5 1≤m≤105,其中 m m m 为操作的数量。
solution
考虑用 LCT 来维护这个东西,主要就是怎么维护虚儿子的信息。
对于 splay 上每个点,记 l m x x / r m x x lmx_x/rmx_x lmxx/rmxx 表示点 x x x 所 “ “ “管辖 ” ” ”的实链部分,从链顶 / / /链底出发,能经过的最大点权和。
然后对每个 x x x 开个 multiset,记一下每个虚儿子的 l m x lmx lmx(只需要知道虚儿子链顶延申的最大距离即可)。
转移就是,考虑从链顶 / / /链底出发,最大距离不经过 x x x,或者到 x x x 就止步,或者在实链上穿过 x x x,或者从 x x x 穿到轻儿子。具体就看代码细节吧。
询问的时候,发现把 u u u 点 access 一下,答案就是 r m x x rmx_x rmxx。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,inf=1e9;
multiset<int>S[N];
int top(int x) {return S[x].empty()?-inf:*S[x].rbegin();}
namespace LCT{
int fa[N],val[N],sum[N],son[N][2],lmx[N],rmx[N];
bool Get(int x) {return son[fa[x]][1]==x;}
bool isroot(int x) {return (!fa[x])||(son[fa[x]][0]!=x&&son[fa[x]][1]!=x);}
void pushup(int x){
sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];
lmx[x]=max(lmx[son[x][0]],sum[son[x][0]]+val[x]+max(0,max(top(x),lmx[son[x][1]])));
rmx[x]=max(rmx[son[x][1]],sum[son[x][1]]+val[x]+max(0,max(top(x),rmx[son[x][0]])));
}
void Rotate(int x){
int y=fa[x],z=fa[y],k=Get(x),l=son[x][k^1];
if(!isroot(y)) son[z][Get(y)]=x;fa[x]=z;
son[y][k]=l,fa[l]=(l?y:0),son[x][k^1]=y,fa[y]=x;
pushup(y),pushup(x);
}
void Splay(int x){
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)) Rotate(Get(x)==Get(y)?y:x);
Rotate(x);
}
}
void Access(int x){
for(int i=0;x;x=fa[i=x]){
Splay(x);
if(son[x][1]) S[x].insert(lmx[son[x][1]]);
if(i) S[x].erase(S[x].find(lmx[i]));
son[x][1]=i,pushup(x);
}
}
}
using namespace LCT;
int n,m;
int main(){
scanf("%d%d",&n,&m),lmx[0]=rmx[0]=-inf;
for(int i=2;i<=n;++i) scanf("%d",&fa[i]);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
for(int i=n;i>=1;--i) pushup(i),S[fa[i]].insert(lmx[i]);
int op,u,v;
while(m--){
scanf("%d",&op);
if(op==1) scanf("%d",&u),Access(u),Splay(u),printf("%d\n",rmx[u]);
else scanf("%d%d",&u,&v),Access(u),Splay(u),val[u]=v;
}
return 0;
}