全局平衡二叉树 GBT
更新日志
2025/02/09:开工。2025/10/28:小修。
概念
全局平衡二叉树 Global BST,你其实可以将其视作静态的LCT。但事实上不需要提前学LCT,也许先学GBT再学LCT也是不错的。
他可以做到 \(O(\log n)\) 单次树上路径修改与查询,优于树剖套平衡树。
思路
首先,我们考虑重链剖分。
我们对于剖分出的每一条重链单独建一棵二叉树,具体地,我们以子树大小为点权,以这条重链的带权中位数为根,然后左右侧递归建树。
这样建树的好处就是保证了树高为 \(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;
}

浙公网安备 33010602011771号