[bzoj2115][高斯消元][线性基]Xor

63 篇文章 0 订阅
4 篇文章 0 订阅

Description

Input

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si
与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。

Output

仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。

Sample Input

5 7

1 2 2

1 3 2

2 4 1

2 5 1

4 5 3

5 3 4

4 3 2

Sample Output

6

HINT

题解

这条路径一定是由一条从1到n的简单路径与一些环组成的。
因为重复走没有贡献会抵消
任意找出图中一条1到n的路径作为ans初值
预处理出图中每个环的异或值,可以在dfs的时候直接搞出来
做出这些环异或值的线性基,ans在线性基上贪心取即可
当我们想取到任意一个环的异或值时,在同一条路径上来回走一次即可取到,由于来回走不回取到这条路径的异或值,可证明可行性

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct node{int x,y,next;LL c;}a[210000];int len,last[51000];
void ins(int x,int y,LL c){len++;a[len].x=x;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
bool v[51000];
LL f[2110000],d[51000];
int ln,n,m;
void dfs(int x)
{
    v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(!v[y])d[y]=d[x]^a[k].c,dfs(y);
        else f[++ln]=d[x]^a[k].c^d[y];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;LL c;
        scanf("%d%d%lld",&x,&y,&c);
        ins(x,y,c);ins(y,x,c);
    }
    memset(v,false,sizeof(v));
    dfs(1);
    LL ans=d[n];
    for(int i=1;i<=ln;i++)
    {
        int p=i;
        for(int j=i+1;j<=ln;j++)if(f[p]<f[j])p=j;
        swap(f[i],f[p]);
        if(f[i]==0){ln=i-1;break;}
        for(int k=62;k>=0;k--)
            if(f[i]&(1LL<<k))
            {
                for(int j=i+1;j<=ln;j++)
                    if(f[j]&(1LL<<k))f[j]^=f[i];
                break;
            }
    }
    for(int i=1;i<=ln;i++)ans=max(ans,ans^f[i]);
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值