bzoj - 2115 Xor —— 线性基
题意:
求图中从1点到n点的所有路径中边权值异或的最大值
思路:
首先要理解,路径可以任意异或环
像图中,从1到n的黑色路径,可以由任意一条红色路径到一个环,走遍环之后,再通过红色路径回到黑色路径上,这时红色路径上的值被异或了两次为0,结果就相当于是黑色路径异或蓝色环
环是没有大小限制的,甚至可以包括黑色路径,所以通过这种方法可以由任意一条从1到n的路径得到所有的路径
剩下的问题一个是求所有环的异或值,可以由一遍深搜得到,每次搜索下一个点时,若这个点被访问过,就会形成一个环
另一个问题是求出所有环之后怎么得到最大的异或值,即从环的异或值中选择一些数使这些数异或起来最大,线性基
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define max_ 200100
#define mod 1000000007
#define inf 0x3f3f3f3f
struct node
{
int to;
ll w;
}zz;
vector< vector<struct node> >v;
int n,m;
ll p[70];
ll value[10000000];
int pl=0;
bool vis[50010];
ll dis[50010];
void dfs(int u)
{
for(int i=0;i<v[u].size();i++)
{
int to=v[u][i].to;
if(vis[to])
{
value[++pl]=dis[u]^dis[to]^v[u][i].w;
}
else
{
vis[to]=true;
dis[to]=dis[u]^v[u][i].w;
dfs(to);
}
}
}
void insert(ll n)
{
for(int i=62;i>=0;i--)
{
if((n>>i)&1)
{
if(p[i])
{
n=n^p[i];
}
else
{
p[i]=n;
break;
}
}
}
}
int main(int argc, char const *argv[]) {
scanf("%d%d",&n,&m);
v.resize(n+1);
for(int i=1;i<=m;i++)
{
int x,y;
ll w;
scanf("%d%d%lld",&x,&y,&w);
if(x!=y)
{
zz.w=w;
zz.to=x;
v[y].push_back(zz);
zz.to=y;
v[x].push_back(zz);
}
}
dfs(1);
for(int i=1;i<=pl;i++)
{
insert(value[i]);
}
ll ans=dis[n];
for(int i=62;i>=0;i--)
{
if((ans^p[i])>ans)
{
ans=ans^p[i];
}
}
printf("%lld\n",ans );
return 0;
}