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

    定义:树链(树上的路径),剖分(把路径分成重链和轻链);

    用途:在一棵树上进行修改、求极值、求和。

    时间复杂度:,数据范围100,000;

    概念:

    • 重儿子:节点u所有的儿子中,siz最大的儿子;

    • 轻儿子:节点u所有的非重儿子的儿子;

    • 重链:所有连续重儿子连接成的链;

    • 轻链(轻边):由节点u跟轻儿子连接的边,最多包含两个定点。

    结论:

    • 所有的重链个数不超过.

    • 所有的轻边的个数不超过;

    • 轻边的size*2<SIZE;

    维护的数据

    • val[u] 节点u的价值

    • tid[u] 节点u的新编号,用于维护线段树

    • valt[u] 节点u的新编号对应的价值,用于维护线段树

    • size[u] 以u为根的子树的节点数; 用于区分重儿子和轻儿子。

    • dep[u] 节点v的深度,根节点的深度为1或0;

    • top[u] 节点u所在链的顶端节点,(u,v)如果为重链,top[u]==top[v],轻链或者轻链重链的结合,top[u]!=top[v].

    • fa[u] 表示u节点的额父亲节点

    实现过程:

    • 邻接表存树

    • DFS1,维护出fa[],dep[]和siz[]

    • DFS2,优先访问重儿子,维护出tid[],valt[],top[]

    • 用tid[]和valt[]建立线段树。

    • 修改,修改u的tid[u]在线段树上的值即可。

    • 查询,两部查询,把查询的链分成重链和轻链查询。如果是复合链,优先查询dep[top[u]]深度深的一端。防止查询越界。

    例题:BZOJ1036树的统计Count

    • 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II。QMAX u v: 询问从点u到点v的路径上的节点的最大权值。 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和。注意:从点u到点v的路径上的节点包括u和v本身。

    • 输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

    • 对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 3e4 + 15;
    int N, Q, u, v;
    //-----------------------邻接表
    struct node
    {
        int id, next;
    } E[maxn << 1]; //双向边
    int head[maxn], num;
    void init()
    {
        memset(head, -1, sizeof(head));
        num = 0;
    }
    void adde(int u, int v)
    {
        E[num].id = v;
        E[num].next = head[u];
        head[u] = num++;
    }
    //--------------------------------DFS1/2
    int val[maxn], valt[maxn], tid[maxn], siz[maxn], top[maxn],
    dep[maxn], fa[maxn];
    int clk;
    void DFS1(int u, int p)
    {
        dep[u] = dep[p] + 1;
        fa[u] = p;
        siz[u] = 1;
        for(int k = head[u]; k != -1; k = E[k].next)
        {
            int id = E[k].id;
            if(id == p) continue;
            DFS1(id, u);
            siz[u] += siz[id];
        }
    }
    void DFS2(int u, int p)
    {
        tid[u] = ++clk;
        valt[clk] = val[u];
        int son = -1;
        for(int k = head[u]; k != -1; k = E[k].next)
        {
            int id = E[k].id;
            if(id == p)continue;
            if(son == -1 || siz[id] > siz[son]) son = id;
        }
        if(son != -1)
        {
            top[son] = top[u];
            DFS2(son, u); 
        }
        for(int k = head[u]; k != -1; k = E[k].next)
        {
            int id = E[k].id;
            if(id == p || id == son)continue;
            top[id] = id;
            DFS2(id, u);
        }
    }
    //--------------------------------线段树
    int mx[maxn*4], sum[maxn*4];
    void build(int id, int l, int r)
    {
        if(l == r) mx[id] = sum[id] = valt[l];
        else
        {
            int mid = (l + r) >> 1;
            build(id << 1, l, mid);
            build(id << 1 | 1, mid + 1, r);
            mx[id] = max(mx[id << 1], mx[id << 1 | 1]);
            sum[id] = sum[id << 1] + sum[id << 1 | 1];
        }
    }
    void update(int id, int l, int r, int u, int vual)
    {
        if(l == r) mx[id] = sum[id] = vual;
        else
        {
            int mid = (l + r) >> 1;
            if(u <= mid)  update(id << 1, l, mid, u, vual);
            else update(id << 1 | 1, mid + 1, r, u, vual);
            mx[id] = max(mx[id << 1], mx[id << 1 | 1]);
            sum[id] = sum[id << 1] + sum[id << 1 | 1];
        }
    }
    int QMax(int id, int L, int R, int l, int r)
    {
        if(R <= r && L >= l) return mx[id];
        else
        {
            int mid = (L + R) >> 1;
            int ret = -INT_MAX;
            if(l <= mid)ret = max(ret, QMax(id << 1, L, mid, l, r));
            if(r >= mid + 1) ret = max(ret, QMax(id << 1 | 1, mid + 1, R, l, r));
            return ret;
        }
    }
    int QMax(int u, int v)
    {
        int ret = -INT_MAX;
        while(top[u] != top[v])
        {
            if(dep[top[u]] < dep[top[v]]) swap(u, v);
            ret = max(ret, QMax(1, 1, N, tid[top[u]], tid[u]));
            u = fa[top[u]];
        }
        if(dep[u] < dep[v]) swap(u, v);
        ret = max(ret, QMax(1, 1, N, tid[v], tid[u]));
        return ret;
    }
    int Qsum(int id, int L, int R, int l, int r)
    {
        if(R <= r && L >= l) return sum[id];
        else
        {
            int mid = (L + R) >> 1;
            int ret = 0;
            if(l <= mid)ret += Qsum(id << 1, L, mid, l, r);
            if(r >= mid + 1) ret += Qsum(id << 1 | 1, mid + 1, R, l, r);
            return ret;
        }
    }
    int Qsum(int u, int v)
    {
        int ret = 0;
        while(top[u] != top[v])
        {
            if(dep[top[u]] < dep[top[v]]) swap(u, v);
            {
                ret += Qsum(1, 1, N, tid[top[u]], tid[u]);
                u = fa[top[u]];
            }
        }
        if(dep[u] < dep[v]) swap(u, v);
        ret += Qsum(1, 1, N, tid[v], tid[u]);
        return ret;
    }
    //--------------------------------主函数
    int main ()
    {
        init();
        scanf("%d",&N);
        for(int i = 1; i < N; i++)
        {
            scanf("%d %d", &u, &v);
            adde(u, v);
            adde(v, u);
        }
        for(int i = 1; i <= N; i++)
            scanf("%d", &val[i]);
        DFS1(1, 0);
        top[1] = 1;
        DFS2(1, 0);
        build(1, 1, N);
        char s[10];
        scanf("%d", &Q);
        for(int i = 1; i <= Q; i++)
        {
            scanf("%s%d%d", s, &u, &v);
            if(!strcmp(s, "QMAX"))
                printf("%d
    ", QMax(u, v));
            else  if(!strcmp(s, "QSUM"))
                printf("%d
    ",Qsum(u, v));
            else
            {
                update(1, 1, N, tid[u], v);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    查找(二)简单清晰的B树、Trie树具体解释
    Java模式(适配器模式)
    程序猿生存定律--交换是职场里一切的根本
    list C++实现
    腾讯面试
    Android4.2.2启动动画前播放视频
    cocos2d0基础篇笔记一
    String.Split()函数
    oracle之表空间(tablespace)、方案(schema)、段(segment)、区(extent)、块(block)
    [一个互联网思想信徒]:今天突破69个听众
  • 原文地址:https://www.cnblogs.com/pealicx/p/7622499.html
Copyright © 2011-2022 走看看