mthoutai

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

题意:一棵树有n个节点,1是根节点,根节点的子节点是单链,然后如今有两种操作0 v x d表示距离节点v为d的节点权值都加x,操作1 v问v节点的权值,初始节点权值都是0。


题解:看了别人的题解才会的,维护两种树,把每条单链都当做一个树状数组维护当前链上每一个节点的权值,还有一种是从根节点開始维护距离为x的节点的权值。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
using namespace std;
const int N = 100005;
int n, q, dis[N], root[N];//数组存深度和单链头节点
vector<int> g[N];
vector<vector<ll> > C;

int lowbit(int x) {
    return x & (-x);
}
//对于根节点的树。en代表距离根节点的长度,假设等于0就不加,由于变量sum加过了
//对于单链的树,st到en向下延伸
void Add(int st, int en, int val, int cur) {
    if (st > en)
        return;
    int sz = C[cur].size();
    for (int i = st; i < sz; i += lowbit(i))
        C[cur][i] += val;
    for (int i = en + 1; i < sz; i += lowbit(i))
        C[cur][i] -= val;
}

ll Sum(int deep, int cur) {
    ll ret = 0;
    int sz = C[cur].size();
    for (int i = deep; i > 0; i -= lowbit(i))
        ret += C[cur][i];
    return ret;
}

void dfs(int u, int pre, int cnt, int cur) {
    dis[u] = cnt;
    root[u] = cur;
    C[cur].push_back(0);
    int sz = g[u].size();
    for (int i = 0; i < sz; i++) {
        int v = g[u][i];
        if (v != pre)
            dfs(v, u, cnt + 1, cur);
    }
}

int main() {
    scanf("%d%d", &n, &q);
    for (int i = 0; i <= n; i++)
        g[i].clear();
    int a, b, op, l, r, x, v, d;
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &a, &b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    int sz = g[1].size();
    C.resize(sz + 5);
    for (int i = 0; i < sz; i++) {
        C[i + 1].push_back(0);//根节点
        dfs(g[1][i], 1, 1, i + 1);
    }
    C[0].resize(N, 0);
    ll sum = 0;//根节点1的权值
    while (q--) {
        scanf("%d", &op);
        if (op == 0) {
            scanf("%d%d%d", &v, &x, &d);
            int cur = root[v];      
            if (d < dis[v])//不会延伸到其它链
                Add(dis[v] - d, dis[v] + d, x, cur);
            else {
                sum += x;
                Add(1, dis[v] + d, x, cur);//单链的子节点延伸
                Add(1, d - dis[v], x, 0);//向根节点延伸
                Add(1, d - dis[v], -x, cur);//反复加的减掉
            }
        }
        else {
            scanf("%d", &v);
            if (v == 1)
                printf("%lld\n", sum);
            else {
                int cur = root[v];
                printf("%lld\n", Sum(dis[v], cur) + Sum(dis[v], 0));//向根节点延伸的单链上的和加上根节点向下延伸的加上的权值
            }
        }
    }
    return 0;
}
posted on 2017-08-05 16:40  mthoutai  阅读(425)  评论(0编辑  收藏  举报