[WC2011]最大XOR和路径

[WC2011]最大XOR和路径

给出一有n个点m条变的无向联通图,定义路径长度为路径上的边权的异或和,询问从起点1到终点n的最大路径长度,\(n≤50000,m≤100000\)

注意到异或和问题,即使已经可以向线性基靠了,之所以为何会推出一下结论,笔者猜测是把线性空间与图论对比,而有考虑到图论中最重要的环,在加上对链的考虑,因为你必须要有一条链从起点达到终点。

先介绍一下结论

  1. 从任意一个点出发到达任意一个点原路返回没有影响,这个显然,因为异或把中间的路径异或掉了,可以理解成瞬间移动,移动到一个点,做了一些事情,再返回,忽略中间过程。

  2. 进入一个环,不走完等于没走,显然根据结论1,原路返回等于没走,于是联系结论1,易知,瞬间移动的目的在于进入一个环,收取边权,于是不难得知问题关键在于环。

  3. 对于还套环,我们只能走完,只能走其中一个子环,如图58794.png,显然从任何一个地方进来,再回到原点出去,必然是其中一个子环,而把一些子环的路径长度加入线性基,必然也可以通过这些子环异或出其他的子环的路径长度,即环的类异或性。

  4. 对于任意一条确定了起点和终点的路径,它的路径变换可以通过与环的异或改变,如图中路径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){
        for(ri int i(63);i>=0;--i)
            if(x>>i){
                if(base[i])x^=base[i];
                else return (void)(base[i]=x);
            }
    }
    il ll max(ll x){
        for(int i(63);i>=0;--i)
            if((x^base[i])>x)x^=base[i];
        return x;
    }
}B;
struct point{
    point*next;int to;ll w;
}*head[50001],*pt;
ll dis[50001];
bool check[50001];
void dfs(int);
il void link(int,int,ll);
template<class free>il void read(free&);
int main(){
    int n,m;read(n),read(m);
    while(m--){
        int u,v;ll w;
        read(u),read(v),read(w);
        link(u,v,w),link(v,u,w);
    }dfs(1),printf("%lld",B.max(dis[n]));
    return 0;
}
void dfs(int x){
    check[x]|=true;
    for(point *i(head[x]);i!=NULL;i=i->next)
        if(check[i->to])B.insert(dis[x]^dis[i->to]^i->w);
        else dis[i->to]=dis[x]^i->w,dfs(i->to);
}
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();
}
il void link(int u,int v,ll w){
    pt=new point,pt->to=v,pt->w=w;
    pt->next=head[u],head[u]=pt;
}

转载于:https://www.cnblogs.com/a1b3c7d9/p/10874642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值