LCT 维护动态带权重剖P9158 题解(2023 激励计划评分 10)
EnofTaiPeople · · 题解
Part1 前言
省选前一直想改这道题,一直不敢,结果现在国赛模拟搬原题强制落实,被我两个小时场切了。
启示:数据结构题还是场切更有意思。
最近的国赛模拟频繁地出现 LCT 或 Top Tree(无一例外都场切了),可能会直接导致我重新开始研究 Top Tree,毕竟我又没有 D/E 类名额。
Part2 问题转化
发现将一个节点与其儿子依次合并不好做,将这棵树重构。
每次将
注意这时
Part3 两个操作
WBTT 这篇文章讲得很清楚,反正我都是学 zx2003 的。
这篇文章里讲了两个操作,access 和 drop,我们每次更改节点 access,即强制将其到根路径上的边变为重边。
然后进行 drop,即将不合法的重边变为轻边,具体地,记录
至于如何动态维护 access 之后链加就行了。
Part4 一些细节
求答案时需要向下跳重链,起初我想用倍增维护(参考 CSP-S 2019 树的重心),但这样是错误的,我白白浪费了好多时间。
事实上,这里需要记录
因为每次切换
Part5 后记
希望我可以从本题衍生出 WBTT 的考场可写作实现方式。
希望 Top Tree 文化能够一直传递下去。
才 2023 年,有的是希望。
Upd:本题并不能衍生出 WBTT 的实现方式,因为那比这个要复杂许多,但我已经学会了复杂度严格、支持 Link-Cut 的 WBTT,却依旧无法做到 考场可写作。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
using ll=long long;
ll a[N],sm[N];
int n,q,rt,cnt,L[N],R[N],fa[N];
int mst[N],d[N];
vector<int>lk[N];
ll lt[N],mn[N],tg[N];
int cl[N],ctg[N];
int lc[N],sl[N];//lc[x]=1->x is'nt wtson
int t[N][2],f[N];
#define ls t[x][0]
#define rs t[x][1]
#define tp(x) (t[f[x]][1]==x)
#define in(x) (t[f[x]][0]==x||tp(x))
void pp(int x){
sl[x]=sl[ls]|sl[rs]|lc[x];
mn[x]=min({mn[ls],mn[rs],lt[x]});
}
void add(int x,ll d){
tg[x]+=d,mn[x]+=d,lt[x]+=d;
}
void adc(int x,int c){
cl[x]=ctg[x]=c;
}
void pd(int x){
if(tg[x]){
if(ls)add(ls,tg[x]);
if(rs)add(rs,tg[x]);
tg[x]=0;
}if(ctg[x]){
adc(ls,ctg[x]),adc(rs,ctg[x]);
ctg[x]=0;
}
}
void ppd(int x){
if(in(x))ppd(f[x]);pd(x);
}
void rot(int x){
int y=f[x],k=tp(x),w=t[x][!k];
t[f[w]=t[x][!k]=y][k]=w;
if(in(y))t[f[y]][tp(y)]=x;
f[x]=f[y],f[y]=x,pp(y);
}
void splay(int x){ppd(x);
for(int y=f[x];in(x);rot(x),y=f[x])
if(in(y))rot(tp(x)^tp(y)?x:y);pp(x);
}
void acs(int x){
for(int y=0;x;x=f[y=x])
splay(x),rs=y,pp(x);
}
int dfs(int x){
sort(lk[x].begin(),lk[x].end());
int nw=x,p;sm[x]=a[x],cl[x]=x;
for(int y:lk[x]){
p=++cnt;
fa[L[p]=nw]=p;
fa[R[p]=dfs(y)]=p;
f[L[p]]=f[R[p]]=p;
if(sm[L[p]]>=sm[R[p]]){
d[p]=L[p];
lc[R[p]]=1,cl[p]=cl[L[p]];
lt[p]=sm[L[p]]-sm[R[p]];
}else{
d[p]=R[p];
lc[L[p]]=1,cl[p]=cl[R[p]];
lt[p]=sm[R[p]]-sm[L[p]];
}
sm[nw=p]=sm[L[p]]+sm[R[p]];
}return mst[x]=nw;
}
vector<int>nd;
void rep(int x,int y){
// cerr<<"rep:"<<x<<" "<<y<<endl;
if(y!=d[x]){
splay(d[x]),lc[d[x]]=1,pp(d[x]);
splay(y),d[x]=y;
int p=cl[y];
splay(x),rs=0;
lt[x]=-lt[x],pp(x);
if(!lc[x])
if(sl[ls]){
for(x=ls;;){
pd(x);
if(sl[rs])x=rs;
else if(lc[x])break;
else x=ls;
}
}else{
while(ls)pd(x),x=ls;
}
// cerr<<x<<" "<<p<<endl;
splay(x),cl[x]=p,adc(rs,p);
// cerr<<cl[x]<<endl;
splay(y),lc[y]=0,pp(y);
}
}
void access(int x){
acs(x),splay(x);
// cerr<<x<<" "<<sl[x]<<" "<<lc[x]<<endl;
while(x&&sl[x]){
while(1){
pd(x);
if(sl[rs])x=rs;
else if(lc[x])break;
else x=ls;
}splay(x);
nd.push_back(x);
x=ls;
}
for(int p:nd)
if(p!=rt)rep(fa[p],p);
nd.clear();
}
void drop(int x){
int mast=x;
acs(x),splay(x),x=ls,splay(x);
while(x&&mn[x]<=0){
while(1){
// cout<<"tg:"<<tg[x]<<endl;
// cout<<"*"<<x<<" "<<ls<<" "<<rs<<" "<<mn[rs]<<" "<<mn[ls]<<" "<<lt[x]<<" "<<mn[x]<<endl;
pd(x);
// cout<<x<<" "<<ls<<" "<<rs<<" "<<mn[rs]<<" "<<mn[ls]<<" "<<lt[x]<<" "<<mn[x]<<endl;
if(mn[rs]<=0)x=rs;
else if(lt[x]<=0)break;
else x=ls;
}
// cerr<<x<<endl;
splay(x);
// cerr<<x<<endl;
nd.push_back(x);
x=ls;
}
for(int p:nd)
if(p!=mast){
// cerr<<p<<" "<<d[p]<<" "<<lt[p]<<endl;
if(d[p]==L[p]){
// cerr<<p<<" "<<lt[p]<<endl;
if(lt[p]<0)rep(p,R[p]);
}else rep(p,L[p]);
}
nd.clear();
}
int main(){
// freopen("copy.in","r",stdin);
// freopen("copy.out","w",stdout);
ios::sync_with_stdio(false);
int i,j,k,l,r,x,y;
cin>>n>>q,cnt=n;ll d;
mn[0]=1e18;
for(x=1;x<=n;++x)cin>>a[x];
for(x=2;x<=n;++x){
cin>>y;
lk[y].push_back(x);
}rt=dfs(1);
for(x=1;x<=cnt;++x)pp(x);
// for(x=n+1;x<=cnt;++x)
// splay(x),printf("x:%d d:%d L:%d R:%d lt:%lld\n",x,::d[x],L[x],R[x],lt[x]);
// for(x=1;x<=cnt;++x)
// printf("x:%d lc:%d\n",x,lc[x]);
while(q--){
cin>>k>>x;
if(k==1){
splay(mst[x]);
// cerr<<cl[mst[x]]<<endl;
printf("%lld\n",a[cl[mst[x]]]);
// if(x==3){
// splay(8),printf("%lld\n",lt[8]);
// }
}else{
cin>>d,access(x),a[x]+=d;
acs(x),splay(x);
// for(int x=1;x<=cnt;++x)
// printf("x:%d ls:%d rs:%d f:%d\n",x,ls,rs,f[x]);
// printf("x:%d mn:%lld\n",x,mn[x]);
// printf("ls:%d mn:%lld\n",ls,mn[ls]);
add(ls,d),pp(x);
// if(!q)exit(0);
// printf("x:%d mn:%lld\n",x,mn[x]);
// cout<<"drop:"<<endl;
drop(x);
// cout<<"end:"<<endl;
}
// for(x=n+1;x<=cnt;++x)
// splay(x),printf("x:%d d:%d L:%d R:%d lt:%lld\n",x,::d[x],L[x],R[x],lt[x]);
// fflush(stdout);
}return 0;
}