• 换根板子


    大概总结一下换根思路, 假设初始根为1, 换根后为$r$.

    1, 单点修改

    直接改即可, 不影响

    2, 子树$x$修改或询问 (需要满足修改具有可减性)

    (1)若x=r, 对全部节点加

    (3)若x不在树链1->r上, 直接加即可

    (3)若x在树链1->r上且x!=r, 全部节点加, 再对x在树链1->r方向上的儿子所在子树减

    //calc(x,y)用来查询点x是否在树链1->y上
    //若在的话返回x在树链1->y上的儿子
    int calc(int x, int y) {
        int f = x, pre = 0, lca;
        while (top[x]!=top[y]) {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            pre = top[x], x = fa[pre];
        }
        if (x==y) lca=x;
        else lca=dep[x]<dep[y]?x:y;
        if (lca!=f) return 0;
        return fa[pre]==f?pre:son[f];
    }
    void update(int x, int v, int rt) {
        if (x==rt) return _update(1,v);
        int t = calc(x,rt);
        if (!t) return _update(x,v);
        _update(1,v),_update(t,-v);
    }
    int query(int x, int rt) {
        if (x==rt) return _query(1);
        int t = calc(x,rt);
        if (!t) return _query(x);
        return _query(1)-_query(t);
    }

    3, 查询lca(x,y), 假设根为1时的lca(x,y)为L

    (1)若树链x->y与1->r无公共路径, 则为L

    (2)若有公共路径(s,t), 则为s,t中深度较大的点

    int lca(int u, int v, int rt) {
        int L = lca(u,v);
        if (_lca(rt,L)!=L) return L;
        int x=_lca(u,rt),y=_lca(v,rt);
        if (dep[x]<dep[y]) swap(x,y);
        return x;
    }
    

     

  • 相关阅读:
    Sherlock and Squares
    [leetcode] Super Ugly Number
    [leetcode] Ugly Number II
    [leetcode] Ugly Number
    [leetcode] Burst Balloons
    菜根谭#268
    菜根谭#267
    菜根谭#266
    菜根谭#265
    菜根谭#264
  • 原文地址:https://www.cnblogs.com/uid001/p/10633624.html
Copyright © 2020-2023  润新知