树链剖分/重链剖分板子(洛谷P3384)

用的是jiangly的板子,支持树上区间修改,区间查询,子树查询

​
using ll = long long;
using i64 = long long;

constexpr i64 inf = 1E18;

// Tag 的 apply 是将 tag 往下传, info 的 apply 是对自身的值进行修改
struct Tag {
    i64 add = 0;

    void apply(const Tag& t) {
        add += t.add;
    }
};

struct Info {
    i64 min = inf;
    i64 max = -inf;
    i64 sum = 0;
    i64 act = 0;

    void apply(const Tag& t) {
        min += t.add;
        max += t.add;
        sum += act * t.add;
    }
};

Info operator+(const Info& a, const Info& b) {
    Info c;
    c.min = std::min(a.min, b.min);
    c.max = std::max(a.max, b.max);
    c.sum = a.sum + b.sum;
    c.act = a.act + b.act;
    return c;
}

template<class Info, class Tag>
struct LazySegmentTree {
    int n;
    std::vector<Info> info;
    std::vector<Tag> tag;

    LazySegmentTree() : n(0) {}

    LazySegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }

    template<class T>
    LazySegmentTree(const std::vector<T>& init_) {
        init(init_);
    }

    void init(int n_, Info v_ = Info()) {
        init(std::vector<Info>(n_, v_));
    }

    template<class T>
    void init(const std::vector<T>& init_) {
        n = init_.size();
        info.assign(4 << (int)std::log2(n), Info());
        tag.assign(4 << (int)std::log2(n), Tag());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }

    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }

    void apply(int p, const Tag& v) {
        info[p].apply(v);
        tag[p].apply(v);
    }

    void push(int p) {
        apply(2 * p, tag[p]);
        apply(2 * p + 1, tag[p]);
        tag[p] = Tag();
    }

    void modify(int p, int l, int r, int x, const Info& v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        push(p);
        if (x < m) {
            modify(2 * p, l, m, x, v);
        }
        else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }

    void modify(int p, const Info& v) {
        modify(1, 0, n, p, v);
    }

    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        push(p);
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }

    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }

    void rangeApply(int p, int l, int r, int x, int y, const Tag& v) {
        if (l >= y || r <= x) {
            return;
        }
        if (l >= x && r <= y) {
            apply(p, v);
            return;
        }
        int m = (l + r) / 2;
        push(p);
        rangeApply(2 * p, l, m, x, y, v);
        rangeApply(2 * p + 1, m, r, x, y, v);
        pull(p);
    }

    void rangeApply(int l, int r, const Tag& v) {
        return rangeApply(1, 0, n, l, r, v);
    }
};

LazySegmentTree<Info, Tag> l;

struct HLD {
    int n;
    std::vector<int> siz, top, dep, parent, in, out, seq;
    std::vector<std::vector<int>> adj;
    int cur;

    HLD() {}

    HLD(int n) {
        init(n);
    }

    void init(int n) {
        this->n = n;
        siz.resize(n);  // 以u为根的子树节点个数
        top.resize(n);  // 重链所在顶点
        dep.resize(n);  // u的深度
        parent.resize(n);  // u的父节点
        in.resize(n);
        out.resize(n);
        seq.resize(n);
        cur = 0;
        adj.assign(n, {});  // son[i]==adj[i][0]
    }

    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    void work(int root = 0) {
        top[root] = root;
        dep[root] = 0;
        parent[root] = -1;
        dfs1(root);
        dfs2(root);
    }

    void dfs1(int u) {
        if (parent[u] != -1) {
            adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
        }
        siz[u] = 1;
        for (auto& v : adj[u]) {
            parent[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }
        }
    }

    void dfs2(int u) {
        in[u] = cur++;
        seq[in[u]] = u;
        for (auto v : adj[u]) {
            top[v] = (v == adj[u][0] ? top[u] : v);
            dfs2(v);
        }
        out[u] = cur;
    }

    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            }
            else {
                v = parent[top[v]];
            }
        }
        return (dep[u] < dep[v]) ? u : v;
    }

    i64 query_path(int u, int v) {
        i64 ans = 0;
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                ans += l.rangeQuery(in[top[u]], in[u] + 1).sum;
                u = parent[top[u]];
            }
            else {
                ans += l.rangeQuery(in[top[v]], in[v] + 1).sum;
                v = parent[top[v]];
            }
        }
        if (dep[u] < dep[v])std::swap(u, v);
        ans += l.rangeQuery(in[v], in[u] + 1).sum;
        return ans;
        
    }

    void update_path(int u, int v, int k) {
        Tag t;
        t.add = k;
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                l.rangeApply(in[top[u]], in[u] + 1, t);
                u = parent[top[u]];
            }
            else {
                l.rangeApply(in[top[v]], in[v] + 1, t);
                v = parent[top[v]];
            }
        }
        if (dep[u] < dep[v])std::swap(u, v);
        l.rangeApply(in[v], in[u] + 1, t);
        
    }

    void update_tree(int u, int k) {
        Tag t;
        t.add = k;
        l.rangeApply(in[u], in[u] + siz[u], t);
    }

    i64 query_tree(int u) {
        return l.rangeQuery(in[u], in[u] + siz[u]).sum;
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, m, r, p;
    // 节点个数, 操作数, 根节点, 模数
    std::cin >> n >> m >> r >> p;

    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        std::cin >> a[i];
    }

    HLD hld(n + 1);
    for (int i = 1; i < n; i++) {
        int x, y;
        std::cin >> x >> y;
        hld.addEdge(x, y);
    }

    hld.work(r);

    std::vector<Info> init(n + 1);
    for (int i = 1; i <= n; i++) {
        init[hld.in[i]].sum = a[i];
        init[hld.in[i]].act = 1;
    }
    l.init(init);

    while (m--) {
        int op, x, y, z;
        std::cin >> op >> x;
        if (op == 1) {
            std::cin >> y >> z;
            hld.update_path(x, y, z);
        }
        else if (op == 2) {
            std::cin >> y;
            std::cout << hld.query_path(x, y) % p << '\n';
        }
        else if (op == 3) {
            std::cin >> z;
            hld.update_tree(x, z);
        }
        else {
            std::cout << hld.query_tree(x) % p << '\n';
        }
    }

    return 0;
}

​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值