zoukankan      html  css  js  c++  java
  • 【bzoj1036】[ZJOI2008]树的统计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”的操作,每行输出一个整数表示要求输出的结果。

    样例输入

    4
    1 2
    2 3
    4 1
    4 2 1 3
    12
    QMAX 3 4
    QMAX 3 3
    QMAX 3 2
    QMAX 2 3
    QSUM 3 4
    QSUM 2 1
    CHANGE 1 5
    QMAX 3 4
    CHANGE 3 6
    QMAX 3 4
    QMAX 2 4
    QSUM 3 4

    样例输出

    4
    1
    2
    2
    10
    6
    5
    6
    5
    16


    题解

    树链剖分模板题,第一次码。。。

    树链剖分就是把一棵树拆为一些链来处理,并用数据结构来维护。

    通常的剖分方法是按照轻重链剖分,每次选取节点最多的子树继承重链,其余视作轻链,重新处理。

    通常用线段树维护权值。

    查询时,如果x和y在同一条链上,那么直接查询,否则一边将x和y往同一条链上靠,一边记录路径上的权值,然后查询。

    代码应该不难理解。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define inf 0x3fffffff
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    int val[30005] , deep[30005] , si[30005] , fa[30005] , bl[30005] , pos[30005] , tot;
    int head[30005] , to[60005] , next[60005] , cnt;
    int maxn[120005] , sum[120005] , n;
    char str[10];
    void add(int x , int y)
    {
        to[++cnt] =y;
        next[cnt] = head[x];
        head[x] = cnt;
    }
    void dfs1(int x)
    {
        si[x] = 1;
        int i , y;
        for(i = head[x] ; i ; i = next[i])
        {
            y = to[i];
            if(y != fa[x])
            {
                deep[y] = deep[x] + 1;
                fa[y] = x;
                dfs1(y);
                si[x] += si[y];
            }
        }
    }
    void dfs2(int x , int c)
    {
        int k = 0 , i , y;
        pos[x] = ++tot;
        bl[x] = c;
        for(i = head[x] ; i ; i = next[i])
        {
            y = to[i];
            if(deep[y] > deep[x] && si[y] > si[k])
                k = y;
        }
        if(k != 0)
        {
            dfs2(k , c);
            for(i = head[x] ; i ; i = next[i])
            {
                y = to[i];
                if(deep[y] > deep[x] && y != k)
                    dfs2(y , y);
            }
        }
    }
    void pushup(int x)
    {
        sum[x] = sum[x << 1] + sum[x << 1 | 1];
        maxn[x] = max(maxn[x << 1] , maxn[x << 1 | 1]);
    }
    void update(int p , int c , int l , int r , int x)
    {
        if(l == r)
        {
            sum[x] = maxn[x] = c;
            return;
        }
        int mid = (l + r) >> 1;
        if(p <= mid)
            update(p , c , lson);
        else
            update(p , c , rson);
        pushup(x);
    }
    int querysum(int b , int e , int l , int r , int x)
    {
        if(b <= l && r <= e)
            return sum[x];
        int mid = (l + r) >> 1 , ans = 0;
        if(b <= mid)
            ans += querysum(b , e , lson);
        if(e > mid)
            ans += querysum(b , e , rson);
        return ans;
    }
    int querymaxn(int b , int e , int l , int r , int x)
    {
        if(b <= l && r <= e)
            return maxn[x];
        int mid = (l + r) >> 1 , ans = -inf;
        if(b <= mid)
            ans = max(ans , querymaxn(b , e , lson));
        if(e > mid)
            ans = max(ans , querymaxn(b , e , rson));
        return ans;
    }
    int solvesum(int x , int y)
    {
        int ans = 0;
        while(bl[x] != bl[y])
        {
            if(deep[bl[x]] < deep[bl[y]])
                swap(x , y);
            ans += querysum(pos[bl[x]] , pos[x] , 1 , n , 1);
            x = fa[bl[x]];
        }
        if(pos[x] > pos[y])
            swap(x , y);
        ans += querysum(pos[x] , pos[y] , 1 , n , 1);
        return ans;
    }
    int solvemaxn(int x , int y)
    {
        int ans = -inf;
        while(bl[x] != bl[y])
        {
            if(deep[bl[x]] < deep[bl[y]])
                swap(x , y);
            ans = max(ans , querymaxn(pos[bl[x]] , pos[x] , 1 , n , 1));
            x = fa[bl[x]];
        }
        if(pos[x] > pos[y])
            swap(x , y);
        ans = max(ans , querymaxn(pos[x] , pos[y] , 1 , n , 1));
        return ans;
    }
    int main()
    {
        int i , x , y , q;
        scanf("%d" , &n);
        for(i = 1 ; i < n ; i ++ )
        {
            scanf("%d%d" , &x , &y);
            add(x , y);
            add(y , x);
        }
        for(i = 1 ; i <= n ; i ++ )
            scanf("%d" , &val[i]);
        dfs1(1);
        dfs2(1 , 1);
        for(i = 1 ; i <= n ; i ++ )
            update(pos[i] , val[i] , 1 , n , 1);
        scanf("%d" , &q);
        while(q -- )
        {
            scanf("%s%d%d" , str , &x , &y);
            switch(str[1])
            {
                case 'H': val[x] = y; update(pos[x] , y , 1 , n , 1); break;
                case 'S': printf("%d
    " , solvesum(x , y)); break;
                default: printf("%d
    " , solvemaxn(x , y));
            }
        }
        return 0;
    }
  • 相关阅读:
    记录下首次开通流量主,开心开心
    微信小程序之本地缓存
    在使用ef的情况下,有Migrations文件,想要直接生成数据库
    CSS 设置圆角div和阴影效果
    小程序UI库(UI组件)
    没有找到可以构建的 NPM 包---小程序开发
    php 接口参数对象转数组方法
    tp5框架获取随机n条
    php图片上传base64接口上传
    php如何实现定时任务,php定时任务方法,最佳解决方案,php自动任务处理
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6180530.html
Copyright © 2011-2022 走看看