2024 ccfcsp认证打卡 2023 12-1
import java.util.*;
public class Main {
static Scanner input = new Scanner(System.in);
static class Node {
int value; // 节点的值
int parent; // 父节点的编号
List<Integer> child; // 子节点列表
Node() {
child = new ArrayList<>();
}
}
static Node[] a = new Node[2005]; // 存储处理后的树结构
static Node[] b = new Node[2005]; // 存储处理前的树结构
static long[] w = new long[2005]; // 节点权重
static int n, m; // 节点数和查询次数
public static void main(String[] args) {
n = input.nextInt(); // 读取节点数
m = input.nextInt(); // 读取查询次数
// 读取每个节点的值和父节点信息,构建树结构
for (int i = 1; i <= n; i++) {
b[i] = new Node();
b[i].value = input.nextInt(); // 读取节点值
}
for (int i = 2; i <= n; i++) {
b[i].parent = input.nextInt(); // 读取父节点编号
b[b[i].parent].child.add(i); // 将当前节点加入父节点的子节点列表中
}
// 处理每次查询
for (int i = 0; i < m; i++) {
int q = input.nextInt(); // 当前查询的节点编号
int root = 1; // 根节点初始为1
// 复制b数组到a数组,用于每次查询的操作
for (int j = 1; j <= n; j++) {
a[j] = new Node();
a[j].value = b[j].value;
a[j].parent = b[j].parent;
a[j].child = new ArrayList<>(b[j].child);
}
// 循环处理直到根节点的子节点为空
while (!a[root].child.isEmpty()) {
long total = addSum(root); // 计算根节点以及其后代节点的权重之和
// 求出差值最小的节点编号作为下一个根节点
solve(root, total);
int tmp = find(root); // 找到差值最小的节点
System.out.print(tmp + " "); // 输出当前根节点编号
// 如果查询节点q是新的根节点的子孙节点,则更新根节点
if (isChild(tmp, q)) {
root = tmp;
} else { // 如果查询节点q不是新的根节点的子孙节点,则移除该节点及其后代节点
int index = a[tmp].parent;
a[index].child.remove(Integer.valueOf(tmp));
}
}
System.out.println(); // 每次查询结束换行输出
}
}
// 计算节点i以及其后代节点的权重之和
static long addSum(int i) {
long ans = a[i].value; // 初始值为节点的值
for (int j = 0; j < a[i].child.size(); j++) {
ans += addSum(a[i].child.get(j)); // 递归求和后代节点的值
}
return ans;
}
// 判断节点k是否是节点i的子孙节点
static boolean isChild(int i, int k) {
if (i == k) return true; // 如果节点相同,则k是i的子孙节点
for (int j = 0; j < a[i].child.size(); j++) {
if (isChild(a[i].child.get(j), k)) { // 递归判断子孙节点
return true;
}
}
return false;
}
// 递归计算节点i的权重w[i],并更新
static void solve(int i, long total) {
w[i] = Math.abs(2 * addSum(i) - total); // 计算节点i的权重
for (int j = 0; j < a[i].child.size(); j++) {
solve(a[i].child.get(j), total); // 递归计算子节点的权重
}
}
// 找出i以及后代节点中w值最小的节点编号,若两者w值相同选最小的
static int find(int i) {
int minn = i; // 初始最小节点为i
for (int j = 0; j < a[i].child.size(); j++) {
int tmp = find(a[i].child.get(j)); // 递归找到子节点中权重最小的节点
if (w[tmp] < w[minn] || (w[tmp] == w[minn] && minn > tmp)) {
minn = tmp; // 更新最小节点编号
}
}
return minn;
}
}