1 条题解

  • 0
    @ 2025-8-24 21:46:10

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zht467
    **

    搬运于2025-08-24 21:46:10,当前版本为作者最后更新于2017-05-05 08:53:13,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    树链剖分固然可以搞。

    但还有另一种做法,可以看出,增加一个节点的权值会对以它为根的整棵子树都有影响,相当于给整棵子树增加一个值。

    而给以某一节点 x 为根的子树增加一个权值也会影响当前子树,节点 y 所增加的值为 dis[y] * z - (dis[x] - 1) * z,每个节点都会增加 -(dis[x] - 1) * z ,询问时只用加上 dis[y] * y 和当前节点 y 的权值。

    给整棵子树增加一个权值可以用 dfs 序 + 线段树搞, dis 数组可以预处理出来。

    ——代码

    #include <cstdio>
    #include <cstring>
    #define LL long long
    #define root 1, 1, n
    #define ls now << 1, l, mid
    #define rs now << 1 | 1, mid + 1, r
    using namespace std;
    const int MAXN = 100001;
    int n, m, cnt, tot;
    int head[MAXN], next[MAXN << 1], to[MAXN << 1], tid[MAXN], size[MAXN];
    LL a[MAXN << 2], b[MAXN << 2], val[MAXN], dis[MAXN];
    inline void add(int x, int y)
    {
        to[cnt] = y;
        next[cnt] = head[x];
        head[x] = cnt++;
    } 
    inline void dfs(int u)
    {
        int i, v; 
        tid[u] = ++tot;
        size[u] = 1;
        for(i = head[u]; i != -1; i = next[i])
        {
            v = to[i];
            if(!size[v])
            {
                dis[v] = dis[u] + 1;
                dfs(v);
                size[u] += size[v];
            }
        }
    }
    inline void push_down(int now)
    {
        a[now << 1] += a[now];
        a[now << 1 | 1] += a[now];
        b[now << 1] += b[now];
        b[now << 1 | 1] += b[now];
        a[now] = b[now] = 0;
    }
    inline void update(LL x, LL y, int ql, int qr, int now, int l, int r)
    {
        if(ql <= l && r <= qr)
        {
            a[now] += x;
            b[now] += y;
            return;
        }
        push_down(now);
        int mid = (l + r) >> 1;
        if(ql <= mid) update(x, y, ql, qr, ls);
        if(mid < qr) update(x, y, ql, qr, rs);
    }
    inline LL query(int u, int x, int now, int l, int r)
    {
        if(l == r) return dis[u] * a[now] + b[now];
        push_down(now);
        int mid = (l + r) >> 1;
        if(x <= mid) return query(u, x, ls);
        else return query(u, x, rs);
    }
    int main()
    {
        int i, x, z;
        LL y;
        scanf("%d %d", &n, &m);
        for(i = 1; i <= n; i++)    scanf("%lld", &val[i]);
        memset(head, -1, sizeof(head));
        for(i = 1; i < n; i++)
        {
            scanf("%d %d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dis[1] = 1;
        dfs(1);
        for(i = 1; i <= n; i++) update(0, val[i], tid[i], tid[i] + size[i] - 1, root);
        for(i = 1; i <= m; i++)
        {
            scanf("%d %d", &z, &x);
            if(z == 1)
            {
                scanf("%lld", &y);
                update(0, y, tid[x], tid[x] + size[x] - 1, root);
            }
            else if(z == 2)
            {
                scanf("%lld", &y);
                update(y, -((dis[x] - 1) * y), tid[x], tid[x] + size[x] - 1, root);
            }
            else printf("%lld\n", query(x, tid[x], root));
        }
        return 0;
    }
    
    • 1

    信息

    ID
    2251
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者