202312-3 树上搜索
- 开始纯模拟做,计算子树权值的时候会有很多重复的计算导致超时。
- 后面观摩了其他人的题解,可以用深度优先搜索解决,只用进行一次搜索即可解决子树权值重复计算问题。
- 找后代节点用的层次遍历。
本题我的做法是,用dfs维护每个节点的及其后代节点的总权值,计算加权后的值,用层次遍历找到后代节点,通过题意判断保留后代节点,还是除此之外的节点。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL weight_total = 0;
int n, m;
int root;
typedef struct node {
int id;
LL my_weight;
LL fixed_weight;
LL family_weight;
vector<int> child;
} mynode;
mynode data[2001];
// 层次遍历找所有子节点包括自己
set<int> find_my_boy(int x) {
queue<int> tep_queue;
// 存储搜索过的节点
set<int> son_set;
tep_queue.push(x);
// son_set.insert(x);
while(tep_queue.size() > 0) {
int node = tep_queue.front();
son_set.insert(node);
mynode cur_node = data[node];
int size = cur_node.child.size();
for(int i = 0; i < size; i++) {
if(data[cur_node.child[i]].fixed_weight > -1) {
tep_queue.push(cur_node.child[i]);
// son_set.insert(cur_node.child[i]);
}
}
tep_queue.pop();
}
return son_set;
}
// 深度优先搜索
LL dfs(int root) {
// cout<<root<<endl;
mynode node = data[root];
// if(node.child.size() == 0) return node.my_weight;
LL tep = node.my_weight;
// cout<<tep<<" ";
int size = node.child.size();
for(int i = 0; i < size; i++) {
if(data[node.child[i]].fixed_weight > -1) {
// cout<<node.child[i]<<"tets";
tep += dfs(node.child[i]);
}
}
// cout<<tep<<" ";
data[root].family_weight = tep;
return tep;
}
void process(int aim) {
// long long weight[2001];
for(int i = 1; i <= n; i++) {
// 初始化信息,无实际意义
data[i].fixed_weight = data[i].my_weight;
data[i].family_weight = 0;
}
LL total = weight_total;
root = 1;
while(1) {
LL min_weight = LLONG_MAX;
int min_node = 0;
int count = 0;
// 深度优先更新加权值,需要维护root节点信息
dfs(root);
for(int i = 1; i <= n; i++) {
if(data[i].fixed_weight < 0) continue;
count++;
data[i].fixed_weight = abs(total - 2 * data[i].family_weight);
// cout<<data[i].fixed_weight<<" ";
if(min_weight > data[i].fixed_weight) {
min_node = i;
min_weight = data[i].fixed_weight;
}
}
if(count == 1) return;
cout<<min_node<<" ";
// cout<<weight_queue.top().fixed_weight<<endl;
// 查找节点
set<int> son_set = find_my_boy(min_node);
bool flag = son_set.count(aim);
// flag=true说明目标节点在当前子树,更新头节点信息
if(flag) root = min_node;
for(int i = 1; i <= n; i++) {
if(data[i].fixed_weight < 0) continue;
if(flag && !son_set.count(data[i].id)) {
total -= data[i].my_weight;
data[i].fixed_weight = -1;
} else if(!flag && son_set.count(data[i].id)) {
total -= data[i].my_weight;
data[i].fixed_weight = -1;
}
}
}
}
int main() {
int test_set[101];
cin>>n>>m;
for(int i = 1; i <= n; i++) {
LL tep;
cin>>tep;
data[i].id = i;
data[i].my_weight = tep;
data[i].fixed_weight = tep;
data[i].family_weight = 0;
weight_total += tep;
}
// data[1].father = 0;
for(int i = 2; i <= n; i++) {
int id;
cin>>id;
// data[i].father = id;
data[id].child.push_back(i);
}
for(int i = 0; i < m; i++) {
cin>>test_set[i];
process(test_set[i]);
cout<<endl;
};
return 0;
}
期间还遇到一个问题
此处最开始赋值为int的最大值,但是只能过80%的样例,可能是加权的时候会有数据超过INT_MAX