ccf 202312-3 树上搜索

本文介绍了如何使用深度优先搜索(DFS)优化一个计算子树权值的问题,避免了重复计算,通过层次遍历找到后代节点并更新加权值,以提高算法效率。作者在代码中展示了如何维护节点信息并处理可能的数据溢出问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值