bzoj-2115 Xor

141 篇文章 0 订阅
44 篇文章 0 订阅

题意:

给出一个有权无向图;

求1到n的路径上的最大异或和;

n<=50000,边权<=10^18;


题解:

由于异或的性质,我们可以知道对于任意一条连通图上的路径的异或和;

都可以由另外一条路径异或若干个环的异或和得来;

因为它们起点和终点都分别是1和n,那么这两个路本身就构成了一个可能经过相同边的环;

而更加显然的是,一个这样的非简单环是可以由若干个简单环组成的;

那么异或了这些简单环之后得到了这个非简单环的异或和,再将原来的路径异或上去抵消掉,就是答案了;

所以处理出所有的简单环,和图中任意一条路径的异或和;

然后答案就是任选几个简单环,它们与路径的最大异或和就是答案;

这里用高斯消元来搞就可以了;

时间复杂度 预处理O(n),高斯消元O(60*环的个数);

环不会太多,大概开到了边数就够了;


代码:


#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 55000
#define M 60
using namespace std;
typedef unsigned long long ll;
vector<int>to[N];
vector<ll>val[N];
int t[N],tot,n;
ll dis[N],a[N<<1],temp;
bool vis[N];
void dfs(int x,ll len)
{
	vis[x]=1;
	if(x==n)	temp=len;
	int i,y;
	for(i=0;i<to[x].size();i++)
	{
		if(!vis[y=to[x][i]])
		{
			dis[y]=len^val[x][i];
			dfs(y,dis[y]);
		}
		else
		{
			if(dis[y]^dis[x]^val[x][i]&&x>y)
				a[++tot]=dis[y]^dis[x]^val[x][i];
		}
	}
}
int main()
{
	int m,i,j,k,x,y;
	ll v,t;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%llu",&x,&y,&v);
		to[x].push_back(y),val[x].push_back(v);
		to[y].push_back(x),val[y].push_back(v);
	}
	dfs(1,0);
	for(i=M,k=0;i>=0;i--)
	{
		for(j=k+1,x=0;j<=tot;j++)
			if((1ll<<i)&a[j])
			{
				x=j;
				break;
			}
		if(!x)	continue;
		else	swap(a[++k],a[x]);
		for(j=1;j<=tot;j++)
		{
			if(k==j)	continue;
			if((1ll<<i)&a[j])
				a[j]^=a[k];
		}
	}
	for(i=1;i<=tot;i++)
		if((temp^a[i])>temp)
			temp^=a[i];
	printf("%llu",temp);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值