洛谷4151 bzoj2115 WC2011最大XOR和路径 线性基

题目链接
题意:给你一个无向连通图,求一条从1到n的路径,使得路径上权值的异或和最大。
对于无向连通图,我们可以重复经过同一条路径多次。根据异或的性质,我们如果从这条路走过去再走回来,答案是不变的。
对于一个无向连通图,如果是一棵树,那么根据刚才的结论,答案就是1到n的这条链的异或和,因为走其他分支都要原路返回,两边异或后答案不变。那么只有图中的环会对答案产生影响。
我们来考虑在当前点走到任何一个环再走回来,答案的变化相当于异或上了环的异或和,因为不在环上的路径被经过了两边抵消掉了,所以我们最后的答案会是任意一条1到n的路径的异或和再异或上若干个环的异或和。任意选一条路径是因为如果有多条路径,那么意味着这条路径与其他路径形成了环,用环的异或和异或当前路径的异或和就是另一条路径的异或和,所以这里的路径可以任选。
最后用线性基求最大的解即可。
实现的话就是dfs一遍,然后在dfs的过程中维护路径的异或和并往要做线性基的集合插入元素。
代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,hed[100010],cnt,vis[100010];
long long ans,dis[100010],xian[20000];
struct node
{
    int to,next;
    long long dis;
}a[200010];
void add(int from,int to,long long dis)
{
    a[++cnt].to=to;
    a[cnt].dis=dis;
    a[cnt].next=hed[from];
    hed[from]=cnt;
}
void insert(long long x)
{
    for(int i=63;i>=0;--i)
    {
        if(x&(1LL<<i))
        {
            if(!xian[i])
            {
                xian[i]=x;
                break;
            }
            else
            x^=xian[i];
        }
    }
}
void dfs(int x)
{
    for(int i=hed[x];i;i=a[i].next)
    {
        int y=a[i].to;
        if(!vis[y])
        {
            dis[y]=dis[x]^a[i].dis;
            vis[y]=1;
            dfs(y);
        }
        else
        insert(dis[x]^a[i].dis^dis[y]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        int x,y;
        long long z;
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dfs(1);
    ans=dis[n];
    for(int i=63;i>=0;--i)
    ans=max(ans,ans^xian[i]);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/80680664