[WC2011]最大XOR和路径
作者:互联网
给出一有n个点m条变的无向联通图,定义路径长度为路径上的边权的异或和,询问从起点1到终点n的最大路径长度,\(n≤50000,m≤100000\)。
解
注意到异或和问题,即使已经可以向线性基靠了,之所以为何会推出一下结论,笔者猜测是把线性空间与图论对比,而有考虑到图论中最重要的环,在加上对链的考虑,因为你必须要有一条链从起点达到终点。
先介绍一下结论
从任意一个点出发到达任意一个点原路返回没有影响,这个显然,因为异或把中间的路径异或掉了,可以理解成瞬间移动,移动到一个点,做了一些事情,再返回,忽略中间过程。
进入一个环,不走完等于没走,显然根据结论1,原路返回等于没走,于是联系结论1,易知,瞬间移动的目的在于进入一个环,收取边权,于是不难得知问题关键在于环。
对于还套环,我们只能走完,只能走其中一个子环,如图,显然从任何一个地方进来,再回到原点出去,必然是其中一个子环,而把一些子环的路径长度加入线性基,必然也可以通过这些子环异或出其他的子环的路径长度,即环的类异或性。
对于任意一条确定了起点和终点的路径,它的路径变换可以通过与环的异或改变,如图中路径1->2->3,异或上最大的环就是1->4->3。
总上这些结论,我们只要dfs把所有的环加入线性基,而选择一条必须选的链与线性基求最大异或和,而求最大异或和的过程包含了对路径的改变,以及瞬间移动获取环上的边权和还套环中环与环的选择,于是可以证明这种做法的正确性。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
using namespace std;
struct linear_base{
ll base[64];
il void insert(ll x){
ri int i;
for(i=63;i>=0;--i)
if(x>>i){
if(base[i])x^=base[i];
else return (void)(base[i]=x);
}
}
il ll max(ll ans){
for(ri int i(63);i>=0;--i)
if((ans^base[i])>ans)ans^=base[i];
return ans;
}
}B;
struct point{
point *next;int to;ll w;
}*pt,*head[500001];
bool check[500001];
ll ans,dis[500001];
void dfs(int,ll);
template<class free>
il void read(free&);
il void link(int,int,ll);
int main(){
int n,m,i,j;ll w;read(n),read(m);
while(m--)read(i),read(j),read(w),
link(i,j,w),link(j,i,w);
dfs(1,0),printf("%lld",B.max(dis[n]));
return 0;
}
il void link(int x,int y,ll w){
pt=new point,pt->to=y,pt->w=w;
pt->next=head[x],head[x]=pt;
}
void dfs(int x,ll n){
check[x]|=true,dis[x]=n;
for(point *i(head[x]);i!=NULL;i=i->next)
if(check[i->to])B.insert(n^i->w^dis[i->to]);
else dfs(i->to,n^i->w);
}
template<class free>
il void read(free &x){
x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
标签:XOR,int,ll,路径,read,异或,WC2011,void 来源: https://www.cnblogs.com/a1b3c7d9/p/10874642.html