zoukankan      html  css  js  c++  java
  • 全局平衡二叉树

    前几天学了全局平衡二叉树,发现这玩意非常牛逼。

    现在我们想要在一棵树上链修改链查询,而我又不想要 (O(nlog^2n)) 的树剖线段树,更不想要常数大的要死的 (O(nlog n)) Lct,这时候全局平衡二叉树的小常数 (O(nlog n)) 就变得非常优越了。

    我们仍然考虑树剖剖出来的重链,对每条重链建出来二叉查找树,满足一条重链的二叉查找树的中序遍历是按深度递增的,这样会使我们在重链上变成区间修改,在新的全局平衡树上我们通过轻边把两条重链连在一起,满足认父不认子,修改和查询的时候我们条重链,然后在二叉查找树上定位区间就可以了,复杂度是 (O(nlog 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;
    }
    
  • 相关阅读:
    什么是透视图?
    Eclipse 视图
    Eclipse 菜单
    Eclipse 窗口说明
    Eclipse 修改字符集
    Eclipse 安装(Oxygen版本)
    Eclipse 教程
    jQuery 教程
    就表单验证说用户体验
    需要配置执行path?no
  • 原文地址:https://www.cnblogs.com/sdlang/p/14546132.html
Copyright © 2011-2022 走看看