全局平衡二叉树
前几天学了全局平衡二叉树,发现这玩意非常牛逼。
现在我们想要在一棵树上链修改链查询,而我又不想要 \(O(n\log^2n)\) 的树剖线段树,更不想要常数大的要死的 \(O(n\log n)\) Lct,这时候全局平衡二叉树的小常数 \(O(n\log n)\) 就变得非常优越了。
我们仍然考虑树剖剖出来的重链,对每条重链建出来二叉查找树,满足一条重链的二叉查找树的中序遍历是按深度递增的,这样会使我们在重链上变成区间修改,在新的全局平衡树上我们通过轻边把两条重链连在一起,满足认父不认子,修改和查询的时候我们条重链,然后在二叉查找树上定位区间就可以了,复杂度是 \(O(n\log n)\)。
建树代码
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;
}