zoukankan      html  css  js  c++  java
  • Codeforces 276E(树状数组)

    题意:一棵树有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
    ", sum);
                else {
                    int cur = root[v];
                    printf("%lld
    ", Sum(dis[v], cur) + Sum(dis[v], 0));//向根节点延伸的单链上的和加上根节点向下延伸的加上的权值
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    python的基本数据类型
    python数据基本运算处理===循环
    多态、多态性和鸭子类型
    菱形问题、类的组合
    类的继承
    面向对象基础
    软件开发三层架构
    logging模块
    json与pickle模块
    Webbrowser模拟百度一下子点击事件
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7290661.html
Copyright © 2011-2022 走看看