bzoj 2115: [Wc2011] Xor(DFS+线性基)

2115: [Wc2011] Xor

Time Limit: 10 Sec   Memory Limit: 259 MB
Submit: 3853   Solved: 1609
[ Submit][ Status][ Discuss]

Description

Input

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

Output

仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。

Sample Input

5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2

Sample Output

6


思路:

先初始化ans = 任意一条1到n路径的异或和

之后DFS找出所有的环,并存下它们的异或和

将所有环的异或和加入线性基,之后贪心就行了,线性基内元素从大到小扫,如果ans异或后更大,那么就异或

最后就是答案


证明:

①如果环没有任意一个点在你那条初始路径上:

你可以专门走到那个环绕一圈后再原路返回,这样就相当于答案异或了那条环上的权值

②如果有一条1到n的路径比你选的这条更优

很显然这条更优的路径和你一开始选的路径构成了一个环,你走一遍这个环就相当于你原本的那条路径没有走过而走的是更优的那条了

③没有三了

#include<stdio.h>
#include<vector>
using namespace std;
#define LL long long
typedef struct
{
	int y;
	LL val;
}Road;
Road now;
vector<Road> G[100005];
int cnt, vis[100005];
LL sc[100005], a[300005], p[66];
void Sech(int u)
{
	int i;
	LL val;
	vis[u] = 1;
	for(i=0;i<G[u].size();i++)
	{
		now = G[u][i];
		val = sc[u]^now.val;
		if(vis[now.y]==1)
			a[++cnt] = val^sc[now.y];
		else
		{
			sc[now.y] = val;
			Sech(now.y);
		}
	}
}
int main(void)
{
	LL ans, val;
	int n, m, i, j, x, y;
	scanf("%d%d", &n, &m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%lld", &x, &y, &val);
		now.y = y, now.val = val;
		G[x].push_back(now);
		now.y = x;
		G[y].push_back(now);
	}
	sc[1] = 0;
	vis[1] = 1;
	Sech(1);
	ans = sc[n];
	for(i=1;i<=cnt;i++)
	{
		for(j=62;j>=0;j--)
		{
			if(a[i]&(1ll<<j))
			{
				if(p[j]==0)
				{
					p[j] = a[i];
					break;
				}
				else
					a[i] ^= p[j];
			}
		}
	}
	for(i=62;i>=0;i--)
	{
		if((ans^p[i])>ans)
			ans = ans^p[i];
	}
	printf("%lld\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值