当前位置:网站首页>Nioke 2022 Summer Multi-School 6 B Eezie and Pie (Difference on the tree + multiplication to find the kth ancestor board)
Nioke 2022 Summer Multi-School 6 B Eezie and Pie (Difference on the tree + multiplication to find the kth ancestor board)
2022-08-08 17:48:00 【Morgannr】
题意:
给定一棵树,要求输出 以 u
为 in the root subtree,How many node weights are satisfied 大于等于 其到 根节点 u
的 距离,u ∈ 1 ~ n
.
思路:
以一棵 根节点为 u
的子树 为例子,我们从 贡献 from the perspective of analyzing the problem.
对于 子树中的某个节点(任意节点,包括 根),我们分析一下 its contribution to the root node.(贡献 指的是 The number of nodes that satisfy the condition)
- 首先,Any node will Make it its own contribution plus
1
. - 其次,假设 节点权值为
w[u]
,它会使得 Its path towards the root nodeu ~ v
(路径长度为w[u]
)上 所有节点 contributions 加上一个1
.
举个例子,Take the example in the question as an example:节点 6
的权值为 3
,Then it will make 6 -> 4 -> 2 -> 1
All points on this path contribute plus 1
.
The first thing I thought was 树链剖分,因为 树链剖分 可以 Converts a certain path in the tree to logn
段连续区间,进而用 线段树 进行 区间修改操作,但是由于其 时间复杂度是 O(n(logn)^2)
级别,题设 范围是 2e6
,Obviously not allowed.
Then what algorithm can be Modify a path in the tree 呢,We can think of a more elegant approach,树上差分.
之前有提到过 一维数组的差分,可以 用 O(1)
The time complexity of completing the operation of adding a certain number to a range,树上差分 也是类似.
具体做法:
- Differential markers on the tree,我们 在
dfs
的过程中完成. - 当向下 Find a node
u
时,我们 令k
等于 其权值w[u]
,前文已经提及,我们 目的是要将u ~ v
This length isk
path as a whole+ 1
,那么转化为 差分操作,就是 在u
节点mark[u] ++
,在v
的父节点mark[fa[v][0]] --
(其中,v
为u
的 第k
个祖先:v = get_fa(u, w[u])
),即可完成.
(此处类比 一维数组差分 帮助理解:在 区间i ~ j
上加上a
,就应当 Make difference arrayc[i] += a,c[j + 1] -= a
)
void dfs(int u, int father) {
int v = get_fa(u, w[u]);
mark[u]++, mark[fa[v][0]]--;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father) continue;
dfs(j, u);
}
}
- 如何求
u
的 第k
个祖先v
,如果暴力的话,显然是会 超时 的,要 倍增 look for(The following board is very important,用于 Find exponentially 节点x
的 第kth
祖先).
int get_fa(int x, int k) {
for (int i = 21; i >= 0; --i)
{
if (k >= (1 << i)) //如果 k If this condition is met, keep jumping,until you reach your destination
{
k -= (1 << i);
x = fa[x][i];
}
}
return x;
}
- 之后进行 第二遍
dfs1
,用于 Merge the difference array of all nodes bottom-upmark[u]
,类比 Convert a 1D difference arrayfor
一遍 前缀和 求 原数组.至此,我们就完成了 Modification operations on paths in the tree.
void dfs1(int u, int father) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father) continue;
dfs1(j, u);
mark[u] += mark[j];
}
}
时间复杂度:
O ( n l o g n ) O(nlogn) O(nlogn)
代码:
#include <bits/stdc++.h>
using namespace std;
//#define map unordered_map
#define int long long
const int N = 2e6 + 10, M = N << 1;
int n;
int h[N], e[M], ne[M], w[N], idx;
int fa[N][22];
int depth[N];
int mark[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs(int root)
{
queue<int> q; q.push(root);
while (q.size())
{
auto t = q.front(); q.pop();
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (depth[j] > depth[t] + 1)
{
depth[j] = depth[t] + 1;
fa[j][0] = t;
for (int k = 1; k <= 21; ++k)
{
fa[j][k] = fa[fa[j][k - 1]][k - 1];
}
q.push(j);
}
}
}
}
void init(int root) //Classic pair fa Array preprocessing operations
{
memset(depth, 0x3f, sizeof depth);
depth[0] = 0, depth[root] = 1;
bfs(root);
}
int get_fa(int x, int k) {
for (int i = 21; i >= 0; --i)
{
if (k >= (1 << i))
{
k -= (1 << i);
x = fa[x][i];
}
}
return x;
}
void dfs(int u, int father) {
int v = get_fa(u, w[u]);
mark[u]++, mark[fa[v][0]]--;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father) continue;
dfs(j, u);
}
}
void dfs1(int u, int father) {
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father) continue;
dfs1(j, u);
mark[u] += mark[j];
}
}
signed main()
{
memset(h, -1, sizeof h);
cin >> n;
int t = n - 1;
while (t--)
{
int u, v; scanf("%lld%lld", &u, &v);
add(u, v), add(v, u);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld", &w[i]);
}
init(1);
dfs(1, -1);
dfs1(1, -1);
for (int i = 1; i <= n; ++i) {
printf("%lld ", mark[i]);
}
return 0;
}
边栏推荐
猜你喜欢
Reprinted, the fragment speaks very well, the big guy
【DB运营管理/开发解决方案】上海道宁为您提供提高工作便利性的集成开发工具——Orange
spark学习笔记(八)——sparkSQL概述-定义/特点/DataFrame/DataSet
CF633C(trie树dfs / 字符串hash + 线性dp)
Cy5反式环辛烯,TCO-Cy5,Cy5 trans-cyclooctene标记生物分子
企业“数字化转型”成功的2个必备条件!
测试/开发程序员停滞不前,倦怠怎么办?突破各种失败和挫折......
开源一夏 | 疫情期间闲来无事,我自制了一个按钮展示框特效来展示我的博客
彻底理解 volatile 关键字及应用场景,面试必问,小白都能看懂!
盘点检索任务中的损失函数
随机推荐
【开源教程2】疯壳·开源编队无人机-硬件资源简介
R file not found problem
【AI玩家养成记 • 第3期】AI开发者必备!史上最适合新手的昇腾AI环境搭建教程!!
R文件找不到问题
记录贴:pytorch学习Part2
【CC3200AI 实验教程4】疯壳·AI语音人脸识别(会议记录仪/人脸打卡机)-GPIO
Tensorflow教程(二)——基本概念与搭建流程
开源一夏 | RuntimeException 子类
Prometheus+Grafana监控系统
QT With OpenGL(泛光)(Bloom)
手机ETF基金开户哪家证券公司好?哪个更安全
牛客2022 暑期多校6 B Eezie and Pie(树上差分 + 倍增求第 kth 祖先板子)
Tensorflow教程(五)——MNIST项目提高
ARP协议详解,小白易懂
pytorch常用语句
使用train_test_split划分训练数据集、测试数据集
DSPE-PEG-NH2,DSPE-PEG-amine,474922-26-4,磷脂-聚乙二醇-氨基科研试剂
glide4入门
为什么需要交叉编译器
【目标检测】小脚本:根据xml批量复制jpg图片