• [BZOJ4034][HAOI2015]树上操作


    4034: [HAOI2015]树上操作

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 5752  Solved: 1850
    [Submit][Status][Discuss]

    Description

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    Input

    第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 
    行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
    第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
     

    Output

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

     

    Sample Input

    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3

    Sample Output

    6
    9
    13

    HINT

     对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

    裸的树剖

    在划分轻重链时处理dfs序

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    char buf[10000000], *ptr = buf - 1;
    inline int readint(){
        int n = 0;
        bool flag = false;
        while(*++ptr < '0' || *ptr > '9') if(*ptr == '-') flag = true;
        while(*ptr >= '0' && *ptr <= '9') n = (n << 1) + (n << 3) + (*ptr++ & 15);
        return flag ? -n : n; 
    }
    typedef long long ll;
    const int maxn = 100000 + 10;
    int n, m;
    struct Edge{
        int to, next;
        Edge(){}
        Edge(int _t, int _n): to(_t), next(_n){}
    }e[maxn * 2];
    int fir[maxn] = {0}, cnt = 0;
    inline void ins(int u, int v){
        e[++cnt] = Edge(v, fir[u]); fir[u] = cnt;
        e[++cnt] = Edge(u, fir[v]); fir[v] = cnt;
    }
    int fa[maxn], siz[maxn], son[maxn];
    void dfs1(int u){
        siz[u] = 1;
        son[u] = 0;
        for(int v, i = fir[u]; i; i = e[i].next){
            v = e[i].to;
            if(v == fa[u]) continue;
            fa[v] = u;
            dfs1(v);
            siz[u] += siz[v];
            if(!son[u] || siz[v] > siz[son[u]]) son[u] = v;
        }
    }
    int val[maxn], w[maxn], top[maxn], in[maxn], out[maxn], dfs_idx = 0;
    void dfs2(int u){
        in[u] = ++dfs_idx;
        w[dfs_idx] = val[u];
        if(!son[u]){
            out[u] = dfs_idx;
            return;
        }
        top[son[u]] = top[u];
        dfs2(son[u]);
        for(int v, i = fir[u]; i; i = e[i].next){
            v = e[i].to;
            if(v == fa[u] || v == son[u]) continue;
            top[v] = v;
            dfs2(v);
        }
        out[u] = dfs_idx;
    }
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    ll sum[maxn * 4], tag[maxn * 4] = {0};
    inline void pushup(int rt){
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void build(int l, int r, int rt){
        if(l == r) sum[rt] = w[l];
        else{
            int mid = l + r >> 1;
            build(lson);
            build(rson);
            pushup(rt);
        }
    }
    inline void pushdown(int rt, int m){
        if(tag[rt]){
            sum[rt << 1] += tag[rt] * (m - (m >> 1));
            sum[rt << 1 | 1] += tag[rt] * (m >> 1);
            tag[rt << 1] += tag[rt];
            tag[rt << 1 | 1] += tag[rt];
            tag[rt] = 0;
        }
    }
    int ql, qr, qv;
    inline void update(int l, int r, int rt){
        if(ql <= l && r <= qr){
            sum[rt] += (ll)qv * (r - l + 1);
            tag[rt] += qv;
        }
        else{
            pushdown(rt, r - l + 1);
            int mid = l + r >> 1;
            if(ql <= mid) update(lson);
            if(qr > mid) update(rson);
            pushup(rt);
        }
    }
    inline ll query(int l, int r, int rt){
        if(ql <= l && r <= qr) return sum[rt];
        else{
            pushdown(rt, r - l + 1);
            int mid = l + r >> 1;
            ll ret = 0;
            if(ql <= mid) ret += query(lson);
            if(qr > mid) ret += query(rson);
            return ret;
        }
    }
    inline void ask(){
        int x = readint();
        ll ans = 0;
        while(top[x] != 1){
            ql = in[top[x]];
            qr = in[x];
            ans += query(1, n, 1);
            x = fa[top[x]];
        }
        ql = in[1];
        qr = in[x];
        ans += query(1, n, 1);
        printf("%lld
    ", ans);
    }
    int main(){
        buf[fread(buf, sizeof(char), sizeof(buf), stdin)] = 0;
        n = readint();
        m = readint();
        for(int i = 1; i <= n; i++) val[i] = readint();
        for(int i = 1; i < n; i++) ins(readint(), readint());
        fa[1] = 0;
        dfs1(1);
        top[1] = 1;
        dfs2(1);
        build(1, n, 1);
        int opt, x;
        while(m--){
            opt = readint();
            if(opt == 1){
                x = readint();
                ql = qr = in[x];
                qv = readint();
                update(1, n, 1);
            }
            else if(opt == 2){
                x = readint();
                ql = in[x];
                qr = out[x];
                qv = readint();
                update(1, n, 1);
            }
            else ask();
        }
        return 0;
    } 
  • 相关阅读:
    队列
    StringBuilder&StringBuffer 源码阅读
    八种基本类型的包装类
    Object 源码阅读
    String 类源码分析
    SpringBoot 启动流程
    BeanDefinition 实例化过程
    BeanDefinition 解析流程【解析所有配置类】
    BeanDefinition 实例
    切面触发过程
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7669072.html
Copyright © 2020-2023  润新知