题意:给你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); }