蓝桥杯 — — 异或和

文章介绍了如何通过深度优先搜索算法处理一个有n个节点的树形结构,对节点的权值进行异或和计算,并支持两种操作:修改节点权值和查询以某个节点为根的子树异或和。作者提供了C++代码示例以演示这一过程。
摘要由CSDN通过智能技术生成

异或和

题目:

请添加图片描述

思路:

题目要求需要对一个有n个节点的树进行求异或和,首先输入n个节点的权值,然后输入边,我们可以使用单向边,因为节点值较小的边不可能是节点值较大的点的子节点,因此我们可以使用一个if判断进行存放单向边,(存放单向边的一个好处是:在进行深度优先搜索的时候可以不用在判断是否又连接到了父节点)

一共有m个操作,对于每一个操作有两种形式,第一种形式是:将点x的权值赋值为y注意:这里不是将x的权值赋值为y的权值】,第二种形式是:查询以x为哦根节点的子树内的所有点权的异或和,这个我们可以通过一个深度优先搜索实现(广度优先搜索也可以)。在进行搜索的时候可以直接进行异或,即将异或的结果作为一个参数进行传递。

代码:

便于理解版本:

// 异或和
#include<iostream>
using namespace std;
#include<vector>
const int N = 1e5 + 100;
vector<int> A(N, 0);   // 用于记录各个点的权值
vector<int> edge[N];   // 用于记录边

// 深度优先搜索
int dfs(int u, vector<int> &A, vector<int> edge[N], int &ans){   // 注意参数使用&是有好处的,其中一个好处是节省内存,并且在一定长度上可以节省开辟新内存的时间
	if(edge[u].size() == 0) return 0;   // 如果该节点的孩子节点是空,即如果该节点是一个叶子节点,就直接退出
	
    // 遍历每一个点的所有子节点
	for(unsigned i = 0;i < edge[u].size();i++){
		int idx = edge[u][i];
		ans ^= A[idx];  // 进行异或
//		cout<<ans<<endl;
		dfs(edge[u][i], A, edge, ans);   // 进行深度优先搜索
	}
	return 0;
}

void solve(){
	int n, m;
	cin>>n>>m;

	// 进行赋权值 
	for(int i = 1;i <= n;i ++) cin>>A[i];
	int u,v;
    // n - 1条边
	for(int i = 0;i < n - 1; i++){
		cin>>u>>v;
        // 进行一次判断,取值较小的点一定不可能是取值较大的点的子节点,因此只需要存单向边即可。
		if(u < v) edge[u].push_back(v);
		else edge[v].push_back(u);
	}
	
	// m次查询 
	int x,y;
	for(int i = 0;i < m; i++){
		int ch;
		cin>>ch;
        // 判断是哪一种情况
		if(ch == 1){
			cin>>x>>y;
			A[x] = y;  // 如果是情况一,就直接改变值即可
		}else{
			cin>>x;
			int ans = A[x];     // 使用ans进行记录以x为根节点的所有子节点的异或和
			dfs(x, A, edge, ans);   // 如果是情况二,就直接进行dfs深度优先搜索,传递参数是:根节点的位置,权值数组,边数组, 异或结果记录值
			cout<<ans<<endl;
		}
	}
	
	return ;
}


int main(){
	int t = 1;
	while(t--){
		solve();
	}
	return 0;
} 

/*
示例:
输入:
4 4
1 2 3 4
1 2
1 3
2 4
2 1
1 1 0
2 1
2 2
输出:
4
5
6
*/

简化版本:

// 异或和
#include<iostream>
using namespace std;
#include<vector>
const int N = 1e5 + 100;
vector<int> A(N, 0);
vector<int> edge[N];
// DFS深度优先搜索 

int dfs(int u, int &ans){
	if(edge[u].size() == 0) return 0;
	for(unsigned i = 0;i < edge[u].size();i++){
		ans ^= A[edge[u][i]];
		dfs(edge[u][i], ans); 
	}
	return 0;
}

void solve(){
	int n, m;
	cin>>n>>m;
	// 进行赋权值 
	for(int i = 1;i <= n;i ++) cin>>A[i];
	int u,v;
	for(int i = 0;i < n - 1; i++){
		cin>>u>>v;
		if(u < v) edge[u].push_back(v);
		else edge[v].push_back(u);
	}
	
	// m次查询 
	int x,y;
	for(int i = 0;i < m; i++){
		int ch;
		cin>>ch;
		if(ch){
			cin>>x>>y;
			A[x] = y;
		}else{
			cin>>x;
			int ans = A[x];
			dfs(x, ans);
			cout<<ans<<endl;
		}
	}
	return ;
}


int main(){
	int t = 1;
	while(t--){
		solve();
	}
	
	return 0;
} 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值