全局平衡二叉树 GBT
更新日志
2025/02/09:开工。
概念
全局平衡二叉树 Global BST,你其实可以将其视作静态的LCT。但事实上不需要提前学LCT,也许先学GBT再学LCT也是不错的。
思路
首先,我们考虑重链剖分。
我们对于剖分出的每一条重链单独建一棵二叉树,具体地,我们以子树大小为点权,以这条重链的带权中位数为根,然后左右侧递归建树。
这样建树的好处就是保证了树高为 \(O(\log n)\) 级别。容易感性理解一下。
对于原图中的轻链,我们考虑认父不认子。具体地,我们将子节点所在新树的根节点的父节点设作原先的父节点,但不更新父节点的子节点信息。
这样我们就保证了每棵新树内的父子信息都是树内的,只有树根会存在一条轻链边。
解决问题
利用GBT可以 \(O(n\log n)\) 解决动态DP问题。
我们对于每个节点,都维护其子树信息和,这个和可以理解为整合、合并的意思。
然后我们考虑修改操作,对于每一棵新树第一次到达的点,也就是重链第一次到达的点,我们更新它的单点值。除此之外,我们对于其一直走父节点走到不存在父节点(包括轻链也没有了),一路所有节点都重新计算其子树信息和。
最后原根节点的答案就是整颗树的子树信息和,我们只需要获取原根节点所在新树的新根节点的子树信息和即可。
模板就直接放例题了。
例题
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define per(i,x,y) for(int i=(x);i>=(y);i--)
#define repl(i,x,y) for(int i=(x);i<(y);i++)
#define file(f) freopen("f.in","r",stdin);freopen("f.out","w",stdout);
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7/*998244353*/;
const int N=1e6+5;
int n,m;
int v[N];
struct matrix{
int m[2][2];
matrix(){memset(m,-0x3f,sizeof(m));}
};
matrix operator*(matrix a,matrix b){
matrix c;
repl(i,0,2)repl(j,0,2)repl(k,0,2)chmax(c.m[i][j],a.m[i][k]+b.m[k][j]);
return c;
}
vec<int> g[N];
int f[N][2];
int siz[N],son[N];
int fa[N];
struct GBT{
matrix val[N],sum[N];
int arr[N],wet[N];
int fath[N],lson[N],rson[N];
inline int wbuild(int lq,int rq){
int l=lq,r=rq;
while(l<r){
int m=l+r>>1;
if((wet[m]-wet[lq-1])*2<wet[rq]-wet[lq-1])l=m+1;
else r=m;
}
if(lq<l){
lson[arr[l]]=wbuild(lq,l-1);
fath[lson[arr[l]]]=arr[l];
}
if(l<rq){
rson[arr[l]]=wbuild(l+1,rq);
fath[rson[arr[l]]]=arr[l];
}
sum[arr[l]]=val[arr[l]];
if(lson[arr[l]])sum[arr[l]]=sum[lson[arr[l]]]*sum[arr[l]];
if(rson[arr[l]])sum[arr[l]]=sum[arr[l]]*sum[rson[arr[l]]];
return arr[l];
}
inline int build(int x){
int now;
now=x;
while(now){
for(auto nxt:g[now]){
if(nxt==fa[now]||nxt==son[now])continue;
fath[build(nxt)]=now;
}
now=son[now];
}
int cnt=0;
now=x;
while(now){
cnt++;
arr[cnt]=now;
wet[cnt]=wet[cnt-1]+siz[now]-siz[son[now]];
now=son[now];
}
return wbuild(1,cnt);
}
inline void change(int x,int y){
val[x].m[1][0]+=y-v[x];v[x]=y;
matrix fst,snd;
while(x){
fst=sum[x];
sum[x]=val[x];
if(lson[x])sum[x]=sum[lson[x]]*sum[x];
if(rson[x])sum[x]=sum[x]*sum[rson[x]];
snd=sum[x];
if(x!=lson[fath[x]]&&x!=rson[fath[x]]){
val[fath[x]].m[0][1]=(val[fath[x]].m[0][0]+=max(snd.m[0][0],snd.m[1][0])-max(fst.m[0][0],fst.m[1][0]));
val[fath[x]].m[1][0]+=snd.m[0][0]-fst.m[0][0];
}
x=fath[x];
}
}
}gbt;
inline void dfs(int now){
siz[now]=1;
for(auto nxt:g[now]){
if(nxt==fa[now])continue;
fa[nxt]=now;
dfs(nxt);
siz[now]+=siz[nxt];
if(siz[nxt]>siz[son[now]])son[now]=nxt;
}
}
inline void dfs2(int now){
gbt.val[now].m[0][0]=f[now][0]=0;
gbt.val[now].m[1][0]=f[now][1]=v[now];
gbt.val[now].m[0][1]=0;
if(son[now]){
dfs2(son[now]);
f[now][0]+=max(f[son[now]][0],f[son[now]][1]);
f[now][1]+=f[son[now]][0];
}
for(auto nxt:g[now]){
if(nxt==fa[now]||nxt==son[now])continue;
dfs2(nxt);
f[now][0]+=max(f[nxt][0],f[nxt][1]);
f[now][1]+=f[nxt][0];
gbt.val[now].m[0][1]=(gbt.val[now].m[0][0]+=max(f[nxt][0],f[nxt][1]));
gbt.val[now].m[1][0]+=f[nxt][0];
}
}
int lst;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,n)cin>>v[i];
repl(i,1,n){
int u,v;cin>>u>>v;
g[u].pub(v);
g[v].pub(u);
}
dfs(1);dfs2(1);
int rt=gbt.build(1);
while(m--){
int x,y;
cin>>x>>y;
x^=lst;
gbt.change(x,y);
cout<<(lst=max(gbt.sum[rt].m[0][0],gbt.sum[rt].m[1][0]))<<"\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】