当前位置:网站首页>【树上差分】CF 1076E. Vasya and a Tree
【树上差分】CF 1076E. Vasya and a Tree
2022-08-06 01:13:00 【行码棋】
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;
}
边栏推荐
- Use WeChat to scan the code to log in
- typescript73-创建自己的类型声明文件(项目内共享类型)
- Live playback including PPT download | Build Online Deep Learning based on Flink & DeepRec
- Oracle study notes combined index (12)
- Horizontal Federated Learning - Gradient Safe Aggregation 1
- 10、SRS4.0源代码分析之WebRTC推流端处理
- 【报错已解决】com.alibaba.fastjson.JSONException: syntax error, expect {, actual [, pos 0
- typescript70-ts中的两种文件类型
- 2022中国大健康展,山东大健康展,济南健康展,健康产业展
- 几种常见SQL分页方式效率比较
猜你喜欢
随机推荐
Idea如何查看代码注释 修改者?
2022山东健博会,中国大健康产业展,产后健康展,婴儿护理展
多线程-理解
数列区间最大值
typescript73-创建自己的类型声明文件(项目内共享类型)
2022 The 4th Shandong International Health Industry Expo, China Health Industry Exhibition
【mysql】--记一次delete删除语句使用别名的坑
One-Class Convolutional Neural Network
SOAP协议学习和使用
How can el-table's data be turned into a picture plus text button?
关于时间格式和获取指定时间的方法
无监督实时系统中的基于YOLOV5_DeepSort和GaitSet外形混合步态的低像素远距离多人模式识别方法
栈、队列、数组的基础代码
DAY24:漏洞复现
Civil law common sense summary 1
【kali-漏洞利用】(3.2)Metasploit基础(中):Armitage工具利用过程
[kali-vulnerability exploitation] (3.2) Metasploit basics (middle): Armitage tool exploitation process
将children数组转为一位数组
session、cookie的区别
【kali-漏洞利用】(3.2)Metasploit基础(下):MSF终端利用过程









