线性基好题!Xortest Path 2021年北京理工清明训练

给你n 个点 m条边 图是联通的 给出一个定义为 一条路径上的 xor路径为 这条路上的 所有边的异或和
给你一个q 查询 每次给出 x,y 问 x点到y点最短的的 xor路径是多少

首先一想 查询最小异或 那就是线性基的题目 但是如何转换为线性基呢
线性基是利用基底 去 获得所有 张成

若此图是一个连通图且无环的话
那么最小xor路径 只能是 x点到y点的路

若此图是一个连通图且有环的话
若x点到y点途径过的点是有环的话 那么可以利用这个环 去获得另一个异或值
所以这个环上的值可以成为基底

所以我们可以先记录一组生成树 然后利用生成树去找环
将环路径 加入到线性基里面去

#include<iostream>
#include<vector>

using namespace std;

const int N = 1e4 + 10;
typedef long long ll;

struct node{
	int x;ll w;
};

struct node2{
	int x,to;ll w;
};

vector<node>v1[N];
vector<node2>v2;

int fa[N];

int get(int x){
	if(fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}

void add(int a,int b,ll c){
	v1[a].push_back({b,c});
	v1[b].push_back({a,c});
}

ll pre[N];
void dfs(int x,int lastt,ll w){
	pre[x] = w;
	for(auto i : v1[x]){
		if(i.x == lastt) continue;
		ll s = w ^ i.w;
		dfs(i.x,x,s);
	}
}

ll d[100];
void insert(ll x){
	for(int i = 62; i >= 0; i--){
		if(x & (1ll << i)){
			if(d[i]) x ^= d[i];
			else{
				d[i] = x;
				break;
			}
		}
	}
	return;
}

ll get_minn(ll x){
	for(int i = 62; i >= 0; i--){
		if(x & (1ll << i)){
			x ^= d[i];
		}
	}
	return x;
}

int main(){
	int n,m,k;
	cin >> n >> m >> k;
	for(int i = 1; i <= n; i++){
		fa[i] = i;
	}
	for(int i = 1; i <= m; i++){
		int x,y;ll z;
		scanf("%d%d%lld",&x,&y,&z);
		int dx = get(x),dy = get(y);
		if(dx != dy){
			fa[dx] = dy;
			add(x,y,z);
		}else{
			v2.push_back({x,y,z});
		}
	}
	
	dfs(1,0,0); 
	
	for(auto i : v2){
		insert(pre[i.x] ^ pre[i.to] ^ i.w);
	}
	
	for(int i = 1; i <= k; i++){
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%lld\n",get_minn(pre[x] ^ pre[y]));
	}
	
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值