全局平衡二叉树
前几天学了全局平衡二叉树,发现这玩意非常牛逼。
现在我们想要在一棵树上链修改链查询,而我又不想要 O(nlog2n) 的树剖线段树,更不想要常数大的要死的 O(nlogn) Lct,这时候全局平衡二叉树的小常数 O(nlogn) 就变得非常优越了。
我们仍然考虑树剖剖出来的重链,对每条重链建出来二叉查找树,满足一条重链的二叉查找树的中序遍历是按深度递增的,这样会使我们在重链上变成区间修改,在新的全局平衡树上我们通过轻边把两条重链连在一起,满足认父不认子,修改和查询的时候我们条重链,然后在二叉查找树上定位区间就可以了,复杂度是 O(nlogn)。
建树代码
int tbuild(int l,int r,int rt)
{
int L = l,R = r,mid;
while (L <= R)
{
mid = L + R >> 1;
if (s[mid] - s[L - 1] <= s[R] - s[mid])
L = mid + 1;
else
R = mid - 1;
}
int u = q[L];
if (!rt)
rt = u;
bel[u] = rt;
sz[u] = r - l + 1;
if (L > l)
lc[u] = tbuild(l,L - 1,rt);
if (L < r)
rc[u] = tbuild(L + 1,r,rt);
return u;
}
void build(int x)
{
int u = x;
while (u)
{
for (int i = head[u];i;i = nxt[i])
{
int v = edge[i];
if (v == son[u])
continue;
build(v);
}
u = son[u];
}
int cnt = 0;u = x;
while (u)
{
q[++cnt] = u;
s[cnt] = s[cnt - 1] + size[u] - size[son[u]];
top[u] = x;
u = son[u];
}
u = tbuild(1,cnt,0);
}
tbuild 中是求出重链的加权中点作为根,比较优。
然后修改操作跟树剖是差不多的
void update(int k,int l,int r,int w)
{
if (l == 1 && r == sz[k])
return (void)(upd(k,w));
int mid = sz[lc[k]];
pushdown(k);
if (l <= mid && lc[k])
update(lc[k],l,min(mid,r),w);
if (r > mid + 1 && rc[k])
update(rc[k],max(1,l - mid - 1),r - mid - 1,w);
if (l <= mid + 1 && r > mid)
val[k] += w,sm[k] += w;
pushup(k);
}
void modify(int x,int y,int w)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x,y);
update(bel[x],1,dep[x] - dep[top[x]] + 1,w);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x,y);
update(bel[x],dep[x] - dep[top[x]] + 1,dep[y] - dep[top[y]] + 1,w);
}
最后是查询操作
long long ask(int k,int l,int r)
{
if (!k)return 0;
if (l == 1 && r == sz[k])
return sm[k];
int mid = sz[lc[k]];
long long ans = 0;
pushdown(k);
if (l <= mid)
ans += ask(lc[k],l,min(mid,r));
if (r > mid + 1)
ans += ask(rc[k],max(1,l - mid - 1),r - mid - 1);
if (l <= mid + 1 && r > mid)
ans += val[k];
return ans;
}
long long query(int x,int y)
{
long long ans = 0;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x,y);
ans += ask(bel[x],1,dep[x] - dep[top[x]] + 1);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x,y);
ans += ask(bel[x],dep[x] - dep[top[x]] + 1,dep[y] - dep[top[y]] + 1);
return ans;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· C# 从零开始使用Layui.Wpf库开发WPF客户端
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!