题意:给你n个点m条带权边的无向图,求1到n路径的最大权值异或和。
题解:我们可以简单的推论出,这条路径肯定是1到n的一条路径再加上几个环,假如我们想从当前节点i去取点j开始一个环,那我们可以有这样一条路径,i->j->环->j-i,对于这条路径,我们的异或贡献为这个环上的值,所以我们只需要找出这个图中的所有的环,形成一个线性基,然后任意取1到n的一条路径,从线性基的最大位开始贪心的取,就能找到答案了。对于寻找环,我们直接dfs,对于有重边的环我们虽然不能找到所有的情况(有重边的环),但是我们可以根据已有的几个环异或出其他环的贡献,例如:
假如我们dfs的顺序为1->2->3->1->4->1的话,我们只能找出1->2->3->1于1->2->3->4->1这两个环,但是我们可以通过异或操作计算出环1->3->4->1的贡献,也就是线性基的定义。
AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
struct edge
{
ll to,next,w;
edge(){}
edge(ll to,ll next,ll w)
{
this->to=to;
this->next=next;
this->w=w;
}
}ed[200005];
ll head[50005],lnum,a[50005];
void addline(ll u,ll v,ll w)
{
ed[lnum]=edge(v,head[u],w);
head[u]=lnum++;
}
struct L_B{
ll d[61],p[61];
ll cnt;
L_B()
{
memset(d,0,sizeof(d));
memset(p,0,sizeof(p));
cnt=0;
}
bool insert(ll val)
{
for (ll i=60;i>=0;i--)
if (val&(1LL<<i))
{
if (!d[i])
{
d[i]=val;
break;
}
val^=d[i];
}
return val>0;
}
ll query_max()
{
ll ret=0;
for (ll i=60;i>=0;i--)
if ((ret^d[i])>ret)
ret^=d[i];
return ret;
}
ll query_min()
{
for (ll i=0;i<=60;i++)
if (d[i])
return d[i];
return 0;
}
void rebuild()
{
for (ll i=60;i>=0;i--)
for (ll j=i-1;j>=0;j--)
if (d[i]&(1LL<<j))
d[i]^=d[j];
for (ll i=0;i<=60;i++)
if (d[i])
p[cnt++]=d[i];
}
ll kthquery(ll k)
{
ll ret=0;
if (k>=(1LL<<cnt))
return -1;
for (ll i=60;i>=0;i--)
if (k&(1LL<<i))
ret^=p[i];
return ret;
}
}q;
L_B merge(const L_B &n1,const L_B &n2)
{
L_B ret=n1;
for (ll i=60;i>=0;i--)
if (n2.d[i])
ret.insert(n2.d[i]);
return ret;
}
void dfs(ll u,ll now)
{
a[u]=now;
for(ll i=head[u];~i;i=ed[i].next)
{
ll to=ed[i].to;
if(a[to]==-1)dfs(to,now^ed[i].w);
else q.insert(now^ed[i].w^a[to]);
}
}
int main()
{
memset(a,-1,sizeof(a));
memset(head,-1,sizeof(head));
ll n,m;
scanf("%lld%lld",&n,&m);
for(ll i=0;i<m;i++)
{
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
addline(u,v,w);
addline(v,u,w);
}
dfs(1,0);
ll ans=a[n];
for(ll i=60;i>=0;i--)
if((ans^q.d[i])>ans)
ans^=q.d[i];
printf("%lld\n",ans);
}