全局平衡二叉树 GBT

更新日志 2025/02/09:开工。

概念

全局平衡二叉树 Global BST,你其实可以将其视作静态的LCT。但事实上不需要提前学LCT,也许先学GBT再学LCT也是不错的。

思路

首先,我们考虑重链剖分

我们对于剖分出的每一条重链单独建一棵二叉树,具体地,我们以子树大小为点权,以这条重链的带权中位数为根,然后左右侧递归建树。

这样建树的好处就是保证了树高为 \(O(\log n)\) 级别。容易感性理解一下。

对于原图中的轻链,我们考虑认父不认子。具体地,我们将子节点所在新树的根节点的父节点设作原先的父节点,但不更新父节点的子节点信息。

这样我们就保证了每棵新树内的父子信息都是树内的,只有树根会存在一条轻链边。

解决问题

利用GBT可以 \(O(n\log n)\) 解决动态DP问题。

我们对于每个节点,都维护其子树信息和,这个和可以理解为整合、合并的意思。

然后我们考虑修改操作,对于每一棵新树第一次到达的点,也就是重链第一次到达的点,我们更新它的单点值。除此之外,我们对于其一直走父节点走到不存在父节点(包括轻链也没有了),一路所有节点都重新计算其子树信息和。

最后原根节点的答案就是整颗树的子树信息和,我们只需要获取原根节点所在新树的新根节点的子树信息和即可。

模板就直接放例题了。

例题

LG4751

代码
#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;
}
posted @   LastKismet  阅读(9)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示