【学习笔记】树链剖分系列三——边权转点权

好像我还能更。

前传1:【学习笔记】树链剖分系列1——树链剖分(重链剖分)——我是不是应该写一篇树链剖分呢

前传2:【学习笔记】树链剖分系列二——LCA

我又来回收伏笔辣:

其实跟下一篇还有点联系来着。

以及:

点权转边权
P4315 月下“毛景树”
P4114 Qtree1
P3038 [USACO11DEC]Grass Planting G

其实啊,边权转点权没啥好讲的,但我为了水博客,单开了一篇

之前我们做的树剖是维护点权,当有题要我们维护边权时,该怎么办呢?

既然写这个,那肯定是要把边权转化成点权,再维护,需要考虑的是转化到什么点上,怎么转化。

考虑树的性质,每个点有且仅有一个父亲,所以,一个点与其父亲之间的边的权值,可以转化成这个点的权值,之后就可以像往常一样维护了。

所以,\(dfs\) 函数改一下

void dfs_deep(int rt, int father, int depth){
    size[rt] = 1;
    fa[rt] = father;
    deep[rt] = depth;

    int max_son = -1;
    for(register int i = head[rt]; i; i = e[i].next){
        int v = e[i].to;
        if(v == father) continue;

        dis[v] = e[i].dis; //转化成点权
        dfs_deep(v, rt, depth + 1);
        size[rt] += size[v];

        if(max_son < size[v]){
            son[rt] = v;
            max_son = size[v];
        }
    }
}

但是仍然有需要注意的。

记得我们上一篇讲LCA的时候,说到了最后跳到的 \(x\) 点是 \(x\)\(y\) 的LCA。(伏笔回收)

LCA是在 \(x\)\(y\) 的路径上深度最小的点,然而在边权转化成点权后,LCA保存的权值是它与它父亲相连的边的权值,不在 \(x\)\(y\) 的路径上。

所以在查询/修改的时候,最后的区间是 \([dfn[x] + 1, dfn[y]]\)

以及,要判断 \(y\) 是不是LCA,即 \(x\) 是否等于 \(y\),若相等,则无需再查询/修改了,不然会造成RE

查询/修改函数:

void Update_Tree(int x, int y, int data){
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        S.Update(1, dfn[top[x]], dfn[x], data);
        x = fa[top[x]];
    }

    if(deep[x] > deep[y]) swap(x, y);
    if(x != y)
        S.Update(1, dfn[x] + 1, dfn[y], data);
}

int Query_Max_Tree(int x, int y){
    int ans = 0;

    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        ans = max(ans, S.Query_Max(1, dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }

    if(deep[x] > deep[y]) swap(x, y);
    if(x != y)
        ans = max(ans, S.Query_Max(1, dfn[x] + 1, dfn[y]));

    return ans;
}

最后,看题:

P4315 月下“毛景树”

裸的边权转点权。

注意些细节:

下方懒标记时要先下放覆盖标记,并且加标记要清零。
对区间覆盖时加标记也要清零。

Code

#include<cstdio>
#include<algorithm>

using namespace std;

const int MAXN = 1e5 + 10;
const int INF = 2147483647;
int n, cnt, num;
int head[MAXN], from[MAXN], to[MAXN];
int dis[MAXN], val[MAXN];
int fa[MAXN], son[MAXN], size[MAXN], deep[MAXN];
int top[MAXN], dfn[MAXN];

struct Edge{
    int to, next, dis;
}e[MAXN << 1];

inline void Add(int u, int v, int w){
    e[++cnt].to = v;
    e[cnt].dis = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void dfs_deep(int rt, int father, int depth){
    size[rt] = 1;
    fa[rt] = father;
    deep[rt] = depth;

    int max_son = -1;
    for(register int i = head[rt]; i; i = e[i].next){
        int v = e[i].to;
        if(v == father) continue;

        dis[v] = e[i].dis;
        dfs_deep(v, rt, depth + 1);
        size[rt] += size[v];

        if(max_son < size[v]){
            son[rt] = v;
            max_son = size[v];
        }
    }
}

void dfs_top(int rt, int top_fa){
    dfn[rt] = ++num;
    top[rt] = top_fa;
    val[num] = dis[rt];

    if(!son[rt]) return;
    dfs_top(son[rt], top_fa);

    for(register int i = head[rt]; i; i = e[i].next){
        int v = e[i].to;
        if(!dfn[v]) dfs_top(v, v);
    }
}

struct Segment_Tree{
    struct Tree{
        int l, r;
        int max;
        int lazy_cover, lazy_add;

        Tree(){
            l = r = 0;
            max = 0;
            lazy_add = 0;
            lazy_cover = -1;
        }
    }tr[MAXN << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        tr[rt].max = max(tr[lson(rt)].max, tr[rson(rt)].max);
    }

    inline void Pushdown(int rt){
        if(tr[rt].lazy_cover != -1){
            tr[lson(rt)].lazy_cover = tr[rt].lazy_cover;
            tr[rson(rt)].lazy_cover = tr[rt].lazy_cover;
            tr[lson(rt)].max = tr[rt].lazy_cover;
            tr[rson(rt)].max = tr[rt].lazy_cover;
            tr[lson(rt)].lazy_add = 0;
            tr[rson(rt)].lazy_add = 0;
            tr[rt].lazy_cover = -1;
        }
        if(tr[rt].lazy_add){
            tr[lson(rt)].lazy_add += tr[rt].lazy_add;
            tr[rson(rt)].lazy_add += tr[rt].lazy_add;
            tr[lson(rt)].max += tr[rt].lazy_add;
            tr[rson(rt)].max += tr[rt].lazy_add;
            tr[rt].lazy_add = 0;
        }
        
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l;
        tr[rt].r = r;

        if(l == r){
            tr[rt].max = val[l];
            return;
        }

        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);

        Pushup(rt);
    }

    void Update(int rt, int pos, int data){
        if(tr[rt].l == tr[rt].r){
            tr[rt].max = data;
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(pos <= mid) Update(lson(rt), pos, data);
        else Update(rson(rt), pos, data);

        Pushup(rt);
    }

    void Change(int rt, int l, int r, int data){
        if(tr[rt].l >= l && tr[rt].r <= r){
            tr[rt].max += data;
            tr[rt].lazy_add += data;

            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Change(lson(rt), l, r, data);
        if(r > mid) Change(rson(rt), l, r, data);

        Pushup(rt);
    }

    void Cover(int rt, int l, int r, int data){
        if(tr[rt].l >= l && tr[rt].r <= r){
            tr[rt].max = data;
            tr[rt].lazy_cover = data;
            tr[rt].lazy_add = 0;

            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Cover(lson(rt), l, r, data);
        if(r > mid) Cover(rson(rt), l, r, data);

        Pushup(rt);
    }

    int Query_Max(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r)
            return tr[rt].max;
        
        Pushdown(rt);

        int ans = 0;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r));
        if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r));

        Pushup(rt);

        return ans;
    }
}S;

void Change_Tree(int x, int y, int data){
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        S.Change(1, dfn[top[x]], dfn[x], data);
        x = fa[top[x]];
    }

    if(deep[x] > deep[y]) swap(x, y);
    if(x != y)
        S.Change(1, dfn[x] + 1, dfn[y], data);
}

void Cover_Tree(int x, int y, int data){
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        S.Cover(1, dfn[top[x]], dfn[x], data);
        x = fa[top[x]];
    }

    if(deep[x] > deep[y]) swap(x, y);
    if(x != y)
        S.Cover(1, dfn[x] + 1, dfn[y], data);
}

int Query_Max_Tree(int x, int y){
    int ans = 0;

    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        ans = max(ans, S.Query_Max(1, dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }

    if(deep[x] > deep[y]) swap(x, y);
    if(x != y)
        ans = max(ans, S.Query_Max(1, dfn[x] + 1, dfn[y]));

    return ans;
}

inline int read(){
    int x = 0, f = 1;
    char c = getchar();

    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}

int main(){
    n = read();
    for(register int i = 1; i <= n - 1; i++){
        int u, v, w;
        u = read(), v = read(), w = read();
        Add(u, v, w);
        Add(v, u, w);
        from[i] = u, to[i] = v;
    }

    dfs_deep(1, 0, 1);
    dfs_top(1, 1);
    S.Build(1, 1, n);

    while(1){
        char opt[10];
        scanf("%s", opt + 1);

        if(opt[1] == 'S') break;
        else if(opt[1] == 'C' && opt[2] == 'h'){
            int k, w, u, v;
            k = read(), w = read();
            u = from[k], v = to[k];

            if(deep[u] < deep[v]) swap(u, v);
            S.Update(1, dfn[u], w);
        }
        else if(opt[1] == 'C' && opt[2] == 'o'){
            int x, y, w;
            x = read(), y = read(), w = read();
            Cover_Tree(x, y, w);
        }
        else if(opt[1] == 'A'){
            int x, y, w;
            x = read(), y = read(), w = read();
            Change_Tree(x, y, w);
        }
        else{
            int x, y;
            x = read(), y = read();
            printf("%d\n", Query_Max_Tree(x, y));
        }
    }

    return 0;
}
posted @ 2022-08-17 22:13  TSTYFST  阅读(332)  评论(0编辑  收藏  举报