全局平衡二叉树

news/2025/9/18 10:52:17/文章来源:https://www.cnblogs.com/Linge-Zzzz/p/19098312

发现自己在大力 DS 这个领域有一些欠缺,所以来补一下。

所谓全局平衡二叉树(GBST)就是 LCT 的静态版本。

我们对树先重剖,然后把每条重链上的点拎出来建一个 BST,满足这个 BST 的中序遍历就是这个重链从上到下遍历得到的序列。然后让这个 BST 的根指向这个点原树上的父亲。

这样此时假如说操作是关于点 \(x\) 到根的路径上的点,那么在新建的树上从点 \(x\) 往上跳,每跳到一棵之前没跳过的 BST,实际上有关的点是在 \(x\) 中序遍历之前的那些点。更进一步,每跳一次,如果 \(x\) 作为一个左儿子跳上去,那么有关的点就是跳上去的点和其左子树里的点。

所以说查询/修改一条根链的复杂度是与树高相关的。我们希望构建一颗树高尽量小的树。考虑这样的方式:对重链上的点构建 BST 时,选取关于轻子树大小 \(+1\) 之和的带权中点作为根,然后递归左右子树建树。

容易发现这样建树的树高是 \(O(\log n)\) 的。无论走一条 BST 边还是非 BST 边,都有子树大小至少为原来的两倍。

下面给出我个人实现的一个模板,使用了标记永久化,用于 P4211。

int fa[N],son[N],siz[N],lsiz[N];
void dfs(int u,int f){fa[u]=f,siz[u]=1;for(int v:G[u]){if(v!=f){dfs(v,u);siz[u]+=siz[v];if(siz[son[u]]<siz[v])son[u]=v;}}lsiz[u]=siz[u]-siz[son[u]];
}
struct node{int fa,ls,rs,sz;int ta,v,s;bool isrt;
}t[N];
int build_chain(int l,int r,vector<int> &b){if(l>=r)return 0;int ssiz=0,csiz=0,mn=INF,idx=0;for(int i=l;i<r;i++)ssiz+=lsiz[b[i]];for(int i=l;i<r;i++){int mx=max(csiz,ssiz-csiz-lsiz[b[i]]);if(mx<mn)idx=i,mn=mx;csiz+=lsiz[b[i]];}int p=b[idx];t[p].sz=r-l;if((t[p].ls=build_chain(l,idx,b))!=0)t[t[p].ls].fa=p;if((t[p].rs=build_chain(idx+1,r,b))!=0)t[t[p].rs].fa=p;return p;
}
int build(int x){vector<int> b;while(x)b.pb(x),x=son[x];for(int u:b)for(int v:G[u])if(v!=fa[u]&&v!=son[u])t[build(v)].fa=u;int rt=build_chain(0,b.size(),b);t[rt].isrt=1;return rt;
}
void pushup(int p){t[p].s=t[t[p].ls].s+t[t[p].rs].s+t[p].sz*t[p].ta;
}
void add(int p){bool fl=1;while(p){if(fl){t[p].ta++;if(t[p].rs){t[t[p].rs].ta--;pushup(t[p].rs);}}fl=(p!=(t[t[p].fa].ls));pushup(p);p=t[p].fa;}
}
int query(int p){int res=0,sz=0;bool fl=1;while(p){if(fl){res+=t[t[p].ls].s;sz+=1+t[t[p].ls].sz;}res+=sz*t[p].ta;fl=(p!=t[t[p].fa].ls);if(t[p].isrt)sz=0;p=t[p].fa;}return res;
}

GBST 的一个重要用途是维护树上 DDP。

仿照树剖做法,我们维护每一棵 BST 上 \(g\) 的矩阵乘积,跳非 BST 边的时候更新即可。

以下是我个人实现的动态 DP 加强版模板代码。

不要忘记 pushup

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int N=1e6+10,INF=0x3f3f3f3f,mod=1e9+7;
struct Mat{int a[2][2];Mat(){memset(a,0,sizeof(a));}inline int *operator[](int x){return a[x-1]-1;}
};
Mat operator*(Mat A,Mat B){Mat C;C[1][1]=max(A[1][1]+B[1][1],A[1][2]+B[2][1]);C[1][2]=max(A[1][1]+B[1][2],A[1][2]+B[2][2]);C[2][1]=max(A[2][1]+B[1][1],A[2][2]+B[2][1]);C[2][2]=max(A[2][1]+B[1][2],A[2][2]+B[2][2]);return C;
}
int n,m,a[N];
vector<int> G[N];
Mat g[N];
int fa[N],siz[N],dep[N],son[N],lsiz[N],f[N][2];
void dfs1(int u,int ft){fa[u]=ft,dep[u]=dep[ft]+1,siz[u]=1;f[u][1]=a[u];for(int v:G[u]){if(v!=ft){dfs1(v,u);f[u][0]+=max(f[v][0],f[v][1]);f[u][1]+=f[v][0];siz[u]+=siz[v];if(siz[son[u]]<siz[v])son[u]=v;}}lsiz[u]=siz[u]-siz[son[u]];
}
void dfs2(int u,int ft){int g0=0,g1=a[u];if(son[u])dfs2(son[u],u);for(int v:G[u]){if(v!=ft&&v!=son[u]){dfs2(v,u);g0+=max(f[v][0],f[v][1]);g1+=f[v][0];}}g[u][1][1]=g[u][1][2]=g0;g[u][2][1]=g1;g[u][2][2]=-INF;
}
int rt;
struct node{Mat v;int fa,ls,rs;bool isrt;
}t[N];
void pushup(int p){t[p].v=g[p];if(t[p].ls)t[p].v=t[t[p].ls].v*t[p].v;if(t[p].rs)t[p].v=t[p].v*t[t[p].rs].v;
}
int build_chain(int l,int r,vector<int> &b){if(l>=r)return 0;int ssiz=0,csiz=0,mn=INF,idx=0;for(int i=l;i<r;i++)ssiz+=lsiz[b[i]];for(int i=l;i<r;i++){int mx=max(csiz,ssiz-csiz-lsiz[b[i]]);if(mx<mn)idx=i,mn=mx;csiz+=lsiz[b[i]];}int p=b[idx];if((t[p].ls=build_chain(l,idx,b))!=0)t[t[p].ls].fa=p;if((t[p].rs=build_chain(idx+1,r,b))!=0)t[t[p].rs].fa=p;pushup(p);return p;
}
int build(int x){vector<int> b;while(x)b.pb(x),x=son[x];for(int u:b)for(int v:G[u])if(v!=fa[u]&&v!=son[u])t[build(v)].fa=u;int rt=build_chain(0,b.size(),b);t[rt].isrt=1;return rt;
}
void Update(int x,int y){g[x][2][1]+=y-a[x];a[x]=y;while(x){if(t[x].isrt){int l0=t[x].v[1][1],l1=t[x].v[2][1];pushup(x);int c0=t[x].v[1][1],c1=t[x].v[2][1];Mat &fm=g[t[x].fa];fm[1][1]+=max(c0,c1)-max(l0,l1);fm[1][2]=fm[1][1];fm[2][1]+=c0-l0;}else pushup(x);x=t[x].fa;}
}
int lans;
int Query(){return max(t[rt].v[1][1],t[rt].v[2][1]);
}
signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<n;i++){int u,v;cin>>u>>v;G[u].pb(v),G[v].pb(u);}dfs1(1,0);dfs2(1,0);rt=build(1);for(int i=1;i<=m;i++){int x,y;cin>>x>>y;x^=lans;Update(x,y);cout<<(lans=Query())<<'\n';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/907049.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Transactional注解的方法里 spring怎么知道我用的是哪个jdbctemplate实例

> 这是一个非常好的问题,它触及了 Spring 框架中声明式事务管理(`@Transactional`)和底层资源管理(`JdbcTemplate`)如何协同工作的核心。 简单直接的回答是:**Spring 并不知道,也不关心你的方法内部使用的是…

根据参数查询

根据参数查询<!-- 根据参数查询--><select id="listByMap" resultMap="ResultMapManage" parameterType="map">select <include refid="Manage_field"/>…

关于非侵入式脑机接口面向C端一个应用想法

目前,脑机接口行业发展如火如荼,但应用仍高度集中在医疗领域,比如运动功能康复等。这类方向不仅技术相对成熟,也更易获得商业回报——毕竟无论是医院还是患者,都更愿意为“恢复健康”买单。然而,若希望脑机接口能…

Blelloch并行扫描算法

本文介绍了一个可以用于并行化串行累计操作的Blelloch算法,可以通过用空间换时间+并行计算的方法,来降低特定计算的时间复杂度。这里我们给出了算法原理的大致介绍,以及基于Numpy的算法代码实现。技术背景 由于现代…

mysql win10

mysql win10https://cloud.tencent.com/developer/article/2392929

「Java EE开发指南」如何用MyEclipse开发Java EE企业应用程序?(二)

「Java EE开发指南」如何用MyEclipse开发Java EE企业应用程序?(二)本教程介绍了Java EE企业应用程序开发入门所需的基本特性、概念和技术。您将学习如何:创建企业应用程序(EAR)项目 添加和删除模块 打包、部署和…

字符串转 python 对象 eval

s = [ { label: "苹果", value: "origin_event_data", icon: "icon-a", color: "#409EFF", bgColor: "#ECF5FF", borderColor:…

牛客刷题-Day1

动态规划1:线性dp、背包问题,区间 https://ac.nowcoder.com/acm/contest/24213?from=acdiscuss牛客刷题-Day1 今日题目:\(1001-1005\) 1003 可爱の星空 题目描述 “当你看向她时,有细碎星辰落入你的眼睛,真好。”…

TENGJUN防水TYPE-C 16PIN连接器技术解析:从结构设计到认证标准的全面解读 - 实践

TENGJUN防水TYPE-C 16PIN连接器技术解析:从结构设计到认证标准的全面解读 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font…

第三届人工智能与自动化控制国际学术会议(AIAC 2025)

第三届人工智能与自动化控制国际学术会议(AIAC 2025) 2025 3rd International Conference on Artificial Intelligence and Automation Control 第三届人工智能与自动化控制国际学术会议(AIAC 2025)将于2025年10月…

图纸安全外发平台全解析

内容概要 图纸安全外发平台是一个专为解决企业图纸外发难题而设计的系统。简单来说,图纸安全外发平台是什么?它就是一个集数据加密、访问控制于一体的在线平台,旨在保障设计图纸在传输过程中的安全性。其中,像Ftra…

webshell流量 - voasem

菜刀、蚁剑、冰蝎、哥斯拉是常见的webshell管理工具。 在攻防演练中,了解其常见webshell管理工具的流量特征对防守方来说十分重要。常见的webshell也在不断发展以绕过安全设备waf的检测,其流量特征也在不断演变,我们…

MMoE学习笔记:利用门控专家网络高效建模多任务关系

MMoE学习笔记:利用门控专家网络高效建模多任务关系MMoE学习笔记:利用门控专家网络高效建模多任务关系 引言 多任务学习(Multi-Task Learning, MTL)已成为大规模推荐系统、计算广告等工业应用领域的标准技术范式。它…

DE23-Lite的串口回环测试

DE23-Lite的串口回环测试DE23-Lite开发板提供了一个UART接口,用户能够通过主机与Agilex 3 FPGA进行串口通信。该接口通过USB Blaster III电路中的FT2232H芯片实现。将USB线连接到DE23-Lite板的Type-C接口和主机之间,…

基于pyspark的双十一美妆数据分析及可视化 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Linux下显卡驱动简单测试

Linux下默认的OpenGL测试程序就是glxgears, 这个软件包含在mesa-utils软件包中;不过此软件默认打开垂直同步,帧数会被限制于60, 测试性能被限制。 所以, 在运行时如下:> vblank_mode =0 glxgears [return] 即可…

大模型三阶段训练方法(LLaMa Factory)

https://blog.csdn.net/2401_85373691/article/details/144685682Rust编程语言群 1036955113 java新手自学群 626070845 java/springboot/hadoop/JVM 群 4915800 Hadoop/mongodb(搭建/开发/运维)Q群481975850GOLang …

算法与数据结构 8 - 线性筛求一般积性函数

引言 昨天和同学做 LOJ #124. 除数函数求和 1,推出了线性筛求一般积性函数的方法,现在写一写。 前置知识 积性函数:对任意互质整数 \(p,q\),\(f(p)\times f(q)=f(pq)\) 的函数。 完全积性函数:对任意整数 \(p,q\)…

SpringMVC使用jasypt加密配置文件 - Commissar

1、引入jasypt依赖库: <!-- Jasypt核心库 --><dependency> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.9.3</version>&l…

三行Python代码实现深度学习推理:Infery全面解析

Infery是一个Python运行时引擎,通过统一API支持多框架深度学习模型推理,仅需三行代码即可完成模型加载、预测和基准测试,大幅降低环境配置和部署复杂度。Infery — 仅用3行Python代码运行深度学习推理 想象一下,通…