• [HAOI2015]树上操作(树链剖分)


    题目链接:P3178 [HAOI2015]树上操作

    树链剖分模板题。。。不会戳

    省选也出模板题,唉。。。

    对于操作一,直接线段树单点修改即可。

    对于操作二,根据同一子树节点编号连续的性质,直接区间修改即可。

    对于操作三,就是查询1->x的答案(太模板了。。。)

    #include <iostream>
    #include <cstdio>
    typedef long long ll;
    using namespace std;
    const ll N = 100010;
    struct seg_tree{
        ll val, tag, l, r;
    }st[4 * N];
    struct node{
        ll pre, to;
    }edge[2 * N];
    ll head[N], tot;
    ll n, m;
    ll w[N], sz[N], pos[N], len, bl[N], dep[N], fa[N], lst[N];
    namespace chain{
        void dfs1(ll x, ll f) {
            sz[x] = 1;
            for (ll i = head[x]; i; i = edge[i].pre) {
                ll y = edge[i].to;
                if (y == f) continue;
                dep[y] = dep[x] + 1;
                fa[y] = x;
                dfs1(y, x);
                sz[x] += sz[y];
            }
        }
        void dfs2(ll x, ll chain) {
            ll k = 0;
            lst[x] = pos[x] = ++len;
            bl[x] = chain;
            for (ll i = head[x]; i; i = edge[i].pre) {
                ll y = edge[i].to;
                if (dep[y] < dep[x]) continue;
                if (sz[y] > sz[k]) {
                    k = y;
                }
            }
            if (k) dfs2(k, chain);
            lst[x] = max(lst[x], lst[k]);
            for (ll i = head[x]; i; i = edge[i].pre) {
                ll y = edge[i].to;
                if (dep[y] < dep[x] || k == y) continue;
                dfs2(y, y);
                lst[x] = max(lst[x], lst[y]);
            }
        }
    }using namespace chain;
    namespace segment_tree{
        void build(ll x, ll l, ll r) {
            st[x].l = l, st[x].r = r;
            if (l == r) return;
            ll mid = (l + r) >> 1;
            build(x << 1, l, mid);
            build(x << 1 | 1, mid + 1, r);
        }
        void update(ll x) {
            if (st[x].tag) {
                st[x << 1].tag += st[x].tag;
                st[x << 1 | 1].tag += st[x].tag;
                st[x << 1].val += (st[x << 1].r - st[x << 1].l + 1) * st[x].tag;
                st[x << 1 | 1].val += (st[x << 1 | 1].r - st[x << 1 | 1].l + 1) * st[x].tag;
                st[x].tag = 0;
            }
        }
        //单点修改 
        void change1(ll x, ll p, ll v) {
            ll l = st[x].l, r = st[x].r;
            if (l == r) {
                st[x].val += v;
                return;
            }
            ll mid = (l + r) >> 1;
            update(x);
            if (p <= mid) change1(x << 1, p, v);
            else change1(x << 1 | 1, p, v);
            st[x].val = st[x << 1].val + st[x << 1 | 1].val;
        }
        //区间修改 
        void change2(ll x, ll L, ll R, ll v) {
            ll l = st[x].l, r = st[x].r;
            if (r < L || l > R) return;
            if (L <= l && r <= R) {
                st[x].tag += v;
                st[x].val += (r - l + 1) * v;
                return;
            }
            update(x);
            change2(x << 1, L, R, v);
            change2(x << 1 | 1, L, R, v);
            st[x].val = st[x << 1].val + st[x << 1 | 1].val;
        }
        //区间求和 
        ll ask(ll x, ll L, ll R) {
            ll l = st[x].l, r = st[x].r;
            if (r < L || l > R) return 0;
            if (L <= l && r <= R) {
                return st[x].val;
            }
            update(x);
            return ask(x << 1, L, R) + ask(x << 1 | 1, L, R);
        }
        ll Qsum(ll x) {
            ll ret = 0;
            while (bl[x] != bl[1]) {
                ret += ask(1, pos[bl[x]], pos[x]);
                x = fa[bl[x]];
            }
            ret += ask(1, pos[bl[x]], pos[x]);
            return ret;
        }
    }using namespace segment_tree;
    void add(ll u, ll v) {
        edge[++tot] = node{head[u], v};
        head[u] = tot;
    }
    int main() {
        cin >> n >> m;
        for (ll i = 1; i <= n; i++) cin >> w[i];
        for (ll i = 1, a, b; i < n; i++) {
            cin >> a >> b;
            add(a, b);
            add(b, a);
        }
        dfs1(1, 0);
        dfs2(1, 1);
        build(1, 1, len);
        for (ll i = 1; i <= n; i++) {
            change1(1, pos[i], w[i]);
        }
        while (m--) {
            ll opt, x, a;
            cin >> opt >> x;
            if (opt == 1) {
                cin >> a;
                change1(1, pos[x], a);
            } else if (opt == 2) {
                cin >> a;
                change2(1, pos[x], lst[x], a);
            } else {
                cout << Qsum(x) << "
    ";
            }
        }
        return 0;
    }
  • 相关阅读:
    Oracle配置手册
    Vim配置手册
    高斯消元
    dp专场的蒟蒻题解
    mac 软件意外退出
    spring security整体流程
    服务启动shell脚本
    nohup 启动命令
    linux service脚本
    docker 安装prometheus和grafna
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12620252.html
Copyright © 2020-2023  润新知