zoukankan      html  css  js  c++  java
  • 【HAOI2015】树上操作

    (题面来自洛谷)

    题目描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    数据范围:N <= 1e5


    分析:简化版的ETT。建立括号序列,操作1、3都很容易解决。为了实现操作2,给序列上的点打标记,表示这里存储的是原节点权值的正/负值。用线段树维护区间和,上推时分别合并正负节点数,区间修改时每个线段树节点值(sum+=val*(pos-neg)),这样就实现了正负节点的区分操作。同时要求移植子树就变成了ETT的模板题,用Splay/FHQ维护即可。
    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    const int maxn(100010);
    typedef long long LL;
    using namespace std;
    int n, m;
    LL wt[maxn];
    int head[maxn], etop;
    struct E {
        int to, nxt;
    } edge[maxn<<1];
    inline void insert(int u, int v) {
        edge[++etop] = (E) {v, head[u]};
        head[u] = etop;
    }
    int fst[maxn], sec[maxn], tmr;
    LL dat[maxn<<1];
    bool cat[maxn<<1];
    void dfs(int u, int pre) {
        fst[u] = ++tmr;
        dat[tmr] = wt[u];
        cat[tmr] = 1;
        for (int i = head[u], v; i; i = edge[i].nxt) {
            if ((v = edge[i].to) == pre) continue;
            dfs(v, u);
        }
        sec[u] = ++tmr;
        dat[tmr] = -wt[u];
        cat[tmr] = 0;
        return;
    }
    namespace Seg_tree {
        #define lc (nd<<1)
        #define rc ((nd<<1)|1)
        #define mid ((l + r) >> 1)
        struct node {
            LL sum;
            int pos, neg;
            friend node operator + (node a, node b) {
                return (node) {a.sum + b.sum, a.pos + b.pos, a.neg + b.neg};
            }
            friend node operator * (node a, LL b) {
                return (node) {a.sum + b * (a.pos-a.neg), a.pos, a.neg};
            }
        } seg[maxn<<3];
        LL tag[maxn<<3];
        inline void update(int nd) {
            seg[nd] = seg[lc] + seg[rc];
        }
        inline void put_tag(int nd, LL val) {
            seg[nd] = seg[nd] * val;
            tag[nd] += val;
        }
        inline void push_down(int nd) {
            put_tag(lc, tag[nd]);
            put_tag(rc, tag[nd]);
            tag[nd] = 0;
        }
        void build(int nd, int l, int r) {
            if (l == r) {
                seg[nd] = (node) {dat[l], cat[l], !cat[l]};
                return;
            }
            build(lc, l, mid);
            build(rc, mid+1, r);
            update(nd);
        }
        void add(int nd, int l, int r, int ql, int qr, LL val) {
            if (l >= ql && r <= qr) {
                put_tag(nd, val);
                return;
            }
            if (r < ql || l > qr) return;
            push_down(nd);
            add(lc, l, mid, ql, qr, val);
            add(rc, mid+1, r, ql, qr, val);
            update(nd);
        }
        LL query(int nd, int l, int r, int ql, int qr) {
            if (l >= ql && r <= qr) {
                return seg[nd].sum;
            }
            if (r < ql || l > qr) return 0;
            push_down(nd);
            return query(lc, l, mid, ql, qr) + query(rc, mid+1, r, ql, qr);
        }
    } using namespace Seg_tree;
    int main() {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; ++i) scanf("%lld", &wt[i]);
        int u, v;
        for (int i = 1; i < n; ++i) {
            scanf("%d %d", &u, &v);
            insert(u, v), insert(v, u);
        }
        dfs(1, 0);
        build(1, 1, 2*n);
        int opt;
        while (m--) {
            scanf("%d %d", &opt, &u);
            if (opt == 3) {
                printf("%lld
    ", query(1, 1, 2*n, 1, fst[u]));
                continue;
            }
            scanf("%d", &v);
            if (opt == 1) {
                add(1, 1, 2*n, fst[u], fst[u], v);
                add(1, 1, 2*n, sec[u], sec[u], v);
            } else add(1, 1, 2*n, fst[u], sec[u], v);
        }
        return 0;
    }
    
  • 相关阅读:
    linux中bin和sbin目录的主要区别
    C# 值类型 引用类型 作为参数传递区别
    绿色免安装电视直播软件viviplayer
    [转]中科大校长建议停止以行政主导的高校评估
    MDS 7.0 使用中的问题 2(数据交换中图元的丢失)
    怪异的慢递公司一统快递
    [转]全国最好的医院列表
    多普达D600 问题集锦
    推荐PDG阅读器UnicornViewer
    [转]《乒乓世界》封面故事:中国男乒直板三人行
  • 原文地址:https://www.cnblogs.com/TY02/p/12229687.html
Copyright © 2011-2022 走看看