树上差分CF 1076E. Vasya and a Tree

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树上差分CF 1076E. Vasya and a Tree相关的知识,希望对你有一定的参考价值。

CF 1076E. Vasya and a Tree|树上差分

题意

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

定义以下两个东西:

  • 函数 d ( i , j ) d(i,j) d(i,j) : 指节点 i i i j j j所经过边的数量。

  • x x x节点的 k k k级子树,指满足以下条件点的集合:

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

    d ( i , j ) ≤ k d(i,j) \\leq k d(i,j)k

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

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

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

思路

题目要求对一段深度的某节点的子树进行加和操作,这种操作类似单纯的一维前缀和差分操作,所以可以在树上进行差分操作。

首先就是将所有的操作离线下来,将所有操作挂在节点上。对应下面的代码

vector<vector<pair<int, int>>> q(n + 1);

for(int i = 1; i <= m; i++)

    int u, d, v;
    cin >> u >> d >> v;
    q[u].push_back(d, v);


接下来的关键点就是如何在树上进行差分操作(对应一维差分 区间左端点的加 和 区间右端点的减)。

因为树中的遍历是基于DFS序的,访问一个子树过后才会访问到另一棵子树

我们在DFS过程中维护差分数组( b [ i ] b[i] b[i]),DFS时携带一个前缀和( s u m sum sum)变量,每访问到一个节点时,先遍历该节点的所有操作,将前缀和(其实就是该路径上差分数组的前缀和,等于当前节点的值)加上操作的值,然后标记差分数组结束的位置(就是在该位置减去操作的那个值)。

当回溯的时候,删除之前打的标记。树遍历是DFS序的,删除之后才会访问到另一棵树相同的深度节点,不会影响 b [ i ] b[i] b[i]的值。

b [ i ] b[i] b[i] : 代表深度为 i i i的节点的标记值

标记:

if(dep[u] + d < n - 1)
    b[dep[u] + d + 1] -= v;//mark

删除标记:

for(auto [d, v] : q[u])

    if(dep[u] + d < n - 1)
        b[dep[u] + d + 1] += v;

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int main()

	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n;
	cin >> n;

	vector<vector<int>> g(n + 1);
	vector<int> dep(n + 1);

	for(int i = 1; i < n; i++)
	
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	

	int m;
	cin >> m;

	vector<vector<pair<int, int>>> q(n + 1);

	for(int i = 1; i <= m; i++)
	
		int u, d, v;
		cin >> u >> d >> v;
		q[u].push_back(d, v);
	

	vector<ll> b(3e5 + 1);
	vector<ll> ans(n + 1);
	function<void(int, int, ll)> dfs = [&](int u, int fa, ll sum)
	
        // 加上标记值
		sum += b[dep[u]]; // minus
        // 枚举节点操作
		for(auto [d, v] : q[u])
		
			sum += v;//累加
			if(dep[u] + d < n - 1)
				b[dep[u] + d + 1] -= v;//mark
		
		ans[u] = sum;
		for(auto v : g[u])
		
			if(v == fa) continue;
			dep[v] = dep[u] + 1;
			dfs(v, u, sum);
		
        // 删除标记
		for(auto [d, v] : q[u])
		
			if(dep[u] + d < n - 1)
				b[dep[u] + d + 1] += v;
		
	;
	dfs(1, -1, 0);
	for(int i = 1; i <= n; i++)
		cout << ans[i] << " \\n"[i == n];
	return 0;

以上是关于树上差分CF 1076E. Vasya and a Tree的主要内容,如果未能解决你的问题,请参考以下文章

树上差分CF 1076E. Vasya and a Tree

树上差分CF 1076E. Vasya and a Tree

CF1076E:Vasya and a Tree(DFS&差分)

CF1076E Vasya and a Tree

Codeforces 1076 E - Vasya and a Tree

CF1076E(dfs+树上差分)