zoukankan      html  css  js  c++  java
  • 树链剖分

    咕咕咕

    一、功能

    • 将树从x到y结点最短路径上所有节点的值都加上z
    • 求树从x到y结点最短路径上所有节点的值之和
    • 将以x为根节点的子树内所有节点值都加上z
    • 求以x为根节点的子树内所有节点值之和

    二、概念

    • 重儿子:对于每一个非叶子节点,它的儿子中 以那个儿子为根的子树节点数最大的儿子 为该节点的重儿子
    • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子
    • 叶子节点没有重儿子也没有轻儿子
    • 重边:一个父亲连接他的重儿子的边称为重边
    • 轻边:剩下的即为轻边
    • 重链:相邻重边连起来的 连接一条重儿子 的链叫重链

    对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链。每一条重链以轻儿子为起点

     

    三、预处理

    dfs1

    要处理几件事情:

    • 标记每个点的深度dep[]
    • 标记每个点的父亲fa[]
    • 标记每个非叶子节点的子树大小(含它自己)
    • 标记每个非叶子节点的重儿子编号son[]

    dfs2

    要预处理几件事情:

    • 标记每个点的新编号
    • 赋值每个点的初始值到新编号上
    • 处理每个点所在链的顶端
    • 处理每条链

    顺序:先处理重儿子再处理轻儿子

    四、树链剖分

    用线段树来写

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    #define mid ((l + r) >> 1)
    #define len (r - l + 1)
    #define lson o << 1,l,mid
    #define rson o << 1 | 1,mid + 1,r
    
    const int maxn = 2e5 + 5,maxm = 1e5 + 5;
    int n,m,r,p;
    int val[maxn],dep[maxn],fa[maxn],siz[maxn],son[maxn],id[maxn],nval[maxn],top[maxn];
    //val点权 ,dep点深度 ,fa父节点编号,siz子树大小,son重儿子,id新编号,nval新编号下的点权数,top当前链顶端结点 
    int res,tot,lazy[maxn * 4],a[maxn * 4];
    int cnt,head[maxn]; 
    struct edge
    {
        int nxt,to;
    }e[maxm * 4];
    
    void add(int a,int b)
    {
        e[++cnt].nxt = head[a];
        e[cnt].to = b;
        head[a] = cnt;
    }
    
    void dfs1(int o,int f,int deep)//o当前结点,f父节点,deep深度 
    {
        dep[o] = deep;
        fa[o] = f; 
        siz[o] = 1; 
        int maxson = -1;
        for(int i = head[o];i;i = e[i].nxt)
        {
            int v = e[i].to;
            if(v == f)
                continue;
            dfs1(v,o,deep+1);
            siz[o] += siz[v];
            if(siz[v] > maxson)
            {
                son[o] = v;
                maxson = siz[v];
            }
        } 
    }
    
    void dfs2(int o,int topf)
    {
        id[o] = ++tot;
        nval[tot] = val[o];
        top[o] = topf;
        if(!son[o])
            return;
        dfs2(son[o],topf);
        for(int i = head[o];i;i = e[i].nxt)
        {
            int v = e[i].to;
            if(v == fa[o] || v == son[o])
                continue;
            dfs2(v,v);
        } 
    }
    
    //---------------线段树---------------- 
    
    void pushdown(int o,int lenn)
    {
        lazy[o << 1] += lazy[o];
        lazy[o << 1 | 1] += lazy[o];
        a[o << 1] += lazy[o] * (lenn - (lenn >> 1));
        a[o << 1 | 1] += lazy[o] * (lenn >> 1);
        a[o << 1] %= p;
        a[o << 1 | 1] %= p;
        lazy[o] = 0;
    }
    
    void build(int o,int l,int r)
    {
        if(l == r)
        {
            a[o] = nval[l] % p;
            return;
        }
        build(lson);
        build(rson);
        a[o] = (a[o << 1] + a[o << 1 | 1])% p;
    }
    
    void update(int o,int l,int r,int ql,int qr,int k)
    {
        if(ql <= l && r <= qr)
        {
            lazy[o] += k;
            a[o] += k * len;
            return;
        }
        if(lazy[o])
            pushdown(o,len);
        if(ql <= mid)
            update(lson,ql,qr,k);
        if(qr > mid)
            update(rson,ql,qr,k);
        a[o] = (a[o << 1] + a[o << 1 | 1])%p;
    }
    
    void query(int o,int l,int r,int ql,int qr)
    {
        if(ql <= l && r <= qr)
        {
            res = (res +a[o])%p;
            return;
        }
        if(lazy[o])
            pushdown(o,len);
        if(ql <= mid)
            query(lson,ql,qr);
        if(qr > mid)
            query(rson,ql,qr);
    }
    
    //---------------线段树—————————————— 
    
    void updr(int l,int r,int k)
    {
        k %= p;
        while(top[l] != top[r])
        {
            if(dep[top[l]] < dep[top[r]])
                swap(l,r);
            update(1,1,n,id[top[l]],id[l],k);
            l = fa[top[l]];
        }
        if(dep[l] > dep[r])
            swap(l,r);
        update(1,1,n,id[l],id[r],k);
    }
    
    int queryr(int l,int r)
    {
        int ans = 0;
        while(top[l] != top[r])
        {
            if(dep[top[l]] < dep[top[r]])
                swap(l,r);
            res = 0;
            query(1,1,n,id[top[l]],id[l]);
            ans = (ans + res)%p;
            l = fa[top[l]];
        }
        if(dep[l] > dep[r])
            swap(l,r);
        res = 0;
        query(1,1,n,id[l],id[r]);
        return (ans + res) % p;
    }
    
    void updson(int o,int k)
    {
        update(1,1,n,id[o],id[o] + siz[o] - 1,k);
    }
    
    int qson(int o)
    {
        res = 0;
        query(1,1,n,id[o],id[o] + siz[o] - 1);
        return res;
    }
    
    int main()
    {
        n = read(),m = read(),r = read(),p = read();
        for(int i = 1;i <= n;i++)
            val[i] = read();
        for(int i = 1;i < n;i++)
        {
            int a = read(),b = read();
            add(a,b);
            add(b,a);
        }
        dfs1(r,0,1);
        dfs2(r,r);
        build(1,1,n); 
        while(m--)
        {
            int opt = read();
            if(opt == 1)
            {
                int x = read(),y = read(),z = read();
                updr(x,y,z);
            }
            else if(opt == 2)
            {
                int x = read(),y = read();
                printf("%d
    ",queryr(x,y));
            }
            else if(opt == 3)
            {
                int x = read(),y = read();
                updson(x,y);
            }
            else
            {
                int x = read();
                printf("%d
    ",qson(x));
            }
        }
        return 0;
    }

     

     

  • 相关阅读:
    读《构建之法》8、9、10章有感
    评论
    复利计算器(4)——jQuery界面美化、自动补全
    送给搭档的“汉堡”
    MFC之TreeCtrl控件使用经验总结
    MFC绘制图片闪烁详解
    MFC 网络编程中::connect返回-1问题
    C++网络编程之select
    C++关于Condition Variable
    Mutex 和 Lock
  • 原文地址:https://www.cnblogs.com/darlingroot/p/11231894.html
Copyright © 2011-2022 走看看