zoukankan      html  css  js  c++  java
  • 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 可以做到在线,但复杂度不优且常数较大

  • 相关阅读:
    SQL SERVER 实现多个数据库之间表的联系,利用临时表枚举表中行数据
    [CCF CSP]201909-2 小明种苹果(续)
    Anaconda 安装 Python 库(MySQLdb)
    [CCF CSP]201903-4 消息传递接口
    [CCF CSP]201609-4 交通规划
    2019年12月CSP考试第三题化学方程式解法
    Leetcode.94.二叉树的中序遍历
    GENIA命名实体数据集解析代码
    git添加新用户
    C#语言 十大经典排序算法动画与解析!(动态演示+代码)(java改写成C# )
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13040179.html
Copyright © 2011-2022 走看看