树上差分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&差分)