poj2182 树状数组
时间: 2023-11-14 18:58:29 浏览: 40
题目链接:[POJ2182](http://poj.org/problem?id=2182)
题目大意:给定一棵 $n$ 个结点的树,每个结点有一个权值 $w_i$。定义一个结点的价值为它到根结点路径上权值的最小值,求所有结点的价值之和。
思路:我们可以用树状数组来维护每个结点的价值,具体的实现方式如下:
1. 首先对树进行 DFS 遍历,求出每个结点的深度 $dep$ 和在 DFS 序列中的位置 $pos$。
2. 定义一个数组 $f$,其中 $f_i$ 表示以结点 $i$ 为根结点的子树中,所有结点的价值之和。显然,根结点的价值就是它本身的权值。
3. 对于每个结点 $i$,我们需要求出它的父结点 $fa_i$ 的价值。假设 $mindep$ 表示 $i$ 到根结点路径上的最小深度,那么 $fa_i$ 的价值就是 $\min(w_i, f_i + w_{fa_i})$。其中,$w_i$ 表示结点 $i$ 的权值,$f_i$ 表示以结点 $i$ 为根结点的子树中,所有结点的价值之和。
4. 对于每个结点 $i$,我们要将其价值加入到树状数组中,同时更新 $f_{i}$。
5. 最后,树中所有结点的价值之和就是树状数组中存储的所有值的和。
代码实现:
相关问题
poj2182树状数组
POJ 2182是一道使用树状数组解决的题目,题目要求对给定的n个数进行排序,并且输出每个数在排序后的相对位置。树状数组是一种用来高效处理前缀和问题的数据结构。
根据引用中的描述,我们可以通过遍历数组a,对于每个元素a[i],可以使用二分查找找到a到a[i-1]中小于a[i]的数的个数。这个个数就是它在排序后的相对位置。
代码中的query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。
最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。
参考代码如下:
```C++
#include <iostream>
#include <cstdio>
using namespace std;
int n, a += y;
}
}
int main() {
scanf("%d", &n);
f = 1;
for (int i = 2; i <= n; i++) {
scanf("%d", &a[i]);
f[i = i & -i;
}
for (int i = n; i >= 1; i--) {
int l = 1, r = n;
while (l <= r) {
int mid = (l + r) / 2;
int k = query(mid - 1);
if (a[i > k) {
l = mid + 1;
}
else if (a[i < k) {
r = mid - 1;
}
else {
while (b[mid]) {
mid++;
}
ans[i = mid;
b[mid = true;
add(mid, -1);
break;
}
}
}
for (int i = 1; i <= n; i++) {
printf("%d\n", ans[i]);
}
return 0;
}
```
这段代码使用了树状数组来完成题目要求的排序功能,其中query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
#### 引用[.reference_title]
- *1* *3* [poj2182Lost Cows——树状数组快速查找](https://blog.csdn.net/aodan5477/article/details/102045839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]
- *2* [poj_2182 线段树/树状数组](https://blog.csdn.net/weixin_34138139/article/details/86389799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"]
[ .reference_list ]
poj Divisibility
POJ Divisibility是一个编程题,要求编写一个程序来确定一系列整数是否可被K整除。输入文件的第一行包含两个整数N和K,用一个空格分隔。第二行包含一系列N个整数,以空格分隔。每个整数的绝对值不大于10000。在输出文件中,如果给定的整数序列可被K整除,则写入单词“Divisible”,否则写入“Not divisible”。
该问题的解决方法可以使用动态规划来实现。我们可以使用一个二维数组dp来记录前i个数产生的余数情况。具体操作如下:
- 初始化dp为1,表示前0个数产生的余数为0。
- 对于每个数a[i],遍历0到K-1的余数j,如果前i-1个数可以产生余数j,则更新dp[i][(j+a[i])%K]和dp[i][(j-a[i])%K]为1。
- 最后判断dp[N]是否为1,如果是,则输出“Divisible”,否则输出“Not divisible”。
举个例子,对于序列17, 5, -21, 15,根据题目中的描述,可以通过添加加号和减号来得到不同的算术表达式,如17+5-21+15=16,17+5-21-15=-14等。在这个例子中,序列是可被7整除的,因为存在一个算术表达式17+5-21-15=-14的结果可以被7整除,但不可被5整除。
因此,根据题目的描述和动态规划的思想,我们可以编写一个程序来解决POJ Divisibility问题。