• CF1076E Vasya and a Tree(树状数组)


    CF1076E Vasya and a Tree(树状数组)

    题目描述

    Vasya 有一棵树,它有 n 个节点,1 号节点为根节点,初始所有点的权值为 0。

    定义以下两个东西:

    1 函数 (d(i,j))

    指节点 i 到 j 所经过边的数量。

    2 x 节点的 k 级子树

    指满足以下条件点的集合:

    ① x 为该点的祖先,规定自己也是自己的祖先。

    (d(i,j) leq k)

    Vasya有 m 条要求要你来解决:

    给出 v,d,x,将以 v 节点的 d 级子树的权值加上 x。

    当处理完 Vasya 所有的要求时,输出所有点的权值。

    数据范围

    第 1 行包括一个整数,n((1 leq n leq 3 cdot 10^{5})),含义如上。

    第 2 行到第 n 行,包括两个整数x和y((1 leq x, y leq n)),用空格隔开,表示两个点之间有一条边。

    第 n+1 行有一个整数m((1 leq m leq 3 cdot 10^{5})),表示有m个要求。

    第 n+2 行到第 n + m + 1行,有三个整数 v,d,x($ 1 leq v_{i} leq n , 0 leq d_{i} leq 10^{9} , 1 leq x_{i} leq 10^{9}$),用空格隔开,含义如上。

    解题思路

    解法一:离线+树状数组

    将修改操作挂在 x 节点上,dfs 遍历整棵树,到 x 节点时将所有操作修改,就是将 (dep_x o dep_{x}+d_x) 都加上 (v_x),然后查询当前深度的权值,继续递归子树,回退时直接减去即可

    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x)
    {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar('
    ');
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y); }
    
    const int N = 400500;
    int h[N], ne[N<<1], to[N<<1], tot, m, n;
    inline void add(int x, int y) {
    	ne[++tot] = h[x], to[h[x] = tot] = y;
    }
    
    ll d[N], ans[N];
    vector<pair<int, int> > v[N];
    
    inline void Add(int x, int k) {
    	for (; x <= n; x += x & -x) d[x] += k;
    }
    inline ll sum(int x) {
    	ll res = 0;
    	for (; x; x -= x & -x) res += d[x];
    	return res;
    }
    
    void dfs(int x, int fa, int dep) {
    	for (auto g: v[x]) Add(dep, g.se), Add(dep + g.fi + 1, -g.se);
    	ans[x] = sum(dep);
    	for (int i = h[x]; i; i = ne[i]) {
    		int y = to[i]; if (y == fa) continue;
    		dfs(y, x, dep + 1);
    	}
    	for (auto g: v[x]) Add(dep, -g.se), Add(dep + g.fi + 1, g.se);
    }
    
    int main() {
    	read(n);
    	for (int i = 1, x, y;i < n; i++)
    		read(x), read(y), add(x, y), add(y, x);
    	read(m);
    	for (int i = 1, p, d, x;i <= m; i++)
    		read(p), read(d), read(x), v[p].push_back(MP(d, x));
    	dfs(1, 0, 1);
    	for (int i = 1;i <= n; i++) printf ("%lld ", ans[i]);
    	return 0;
    }
    

    解法二:维护矩形

    容易发现将 (x o (dfn[x],dep[x])) 可以很好的表示此题中的关系,修改时首先在 x 的子树内可以用 dfs 序来解决,深度要求第二维解决,由此转化为若干矩阵相加,单点求值,本质和第一个方法一样

    可以用树状数组或 kd-tree 维护,其中 kd-tree 可以做到在线,但复杂度不优且常数较大

  • 相关阅读:
    通用类 GetCPU 返回系统CPU占用百分比
    通用类 NVCSpecialized 序列和反序列化
    通用类 Logger 日志类
    第07组 Alpha冲刺 (1/6)(组长)
    第07组 Alpha冲刺 (5/6)(组长)
    第07组 Alpha冲刺 (6/6)(组长)
    第07组 Alpha冲刺 (2/6)(组长)
    第07组 Alpha冲刺 总结(组长)
    第07组 Alpha冲刺 (4/6)(组长)
    第07组 Alpha冲刺 (3/6)(组长)
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13040179.html
Copyright © 2020-2023  润新知