BZOJ 2115 [Wc2011] Xor

给定边权为非负的无向图,求1到n边权异或和最大的路径(可以重复经过点和边)。
n50000,m100000,0ei1018

PoPoQQQ:
http://blog.csdn.net/popoqqq/article/details/39804075
一条路径的异或和可以化为一条1到n的简单路径和一些简单环的异或和,我们首先DFS求出任意一条1到n的简单路径以及图中所有线性无关的环(线性基)。

度娘:
1.线性基能相互异或得到原集合的所有相互异或得到的值。
2.线性基是满足性质1的最小的集合。
3.线性基没有异或和为0的子集。

用高斯消元求线性基,其结果的特点是最高位单调,且每个数的最高位只出现在这个数上。
(e.g 110,011->101,011)

最后贪心求解即可。

线性基+dfs生成树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
template<class T>void sc(T &x){
    int f=1;x=0;char c;
    while(c=getchar(),c<48)if(c=='-')f=-1;
    do x=x*10+(c^48);
    while(c=getchar(),c>47);
    x*=f;
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar('0'+x%10);
}
template<class T>void pt(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(!x)putchar('0');
    else nt(x);
}
//----------------------------
const int maxn=50004;
const int maxm=100005;

int n,m;

int last[maxm],ecnt;
struct Edge{
    int to;ll w;int nxt;
}edge[maxm<<1];
void ins(int u,int v,ll w){
    edge[++ecnt]=(Edge){v,w,last[u]};
    last[u]=ecnt;
}

ll d[maxm<<1];//*
ll key[maxn];
int tot;
bool vis[maxn];
void dfs(int x){
    vis[x]=true;
    for(int i=last[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(vis[y]){
            ll t=key[x]^key[y]^edge[i].w;
            if(t)d[++tot]=t;
        }
        else{
            key[y]=key[x]^edge[i].w;
            dfs(y);
        }
    }
}
void gospoly(){
    int i,k=0;
    for(ll t=1ll<<62;t;t>>=1){
        for(i=k+1;i<=tot;i++)
            if(d[i]&t)break;
        if(i>tot)continue;
        swap(d[++k],d[i]);
        for(int j=1;j<=tot;j++)
            if(j!=k&&(d[j]&t))d[j]^=d[k];
    }
}


int main(){
    sc(n);sc(m);
    ll w;
    for(int u,v,i=1;i<=m;i++){
        sc(u);sc(v);sc(w);
        ins(u,v,w);
        ins(v,u,w);
    }
    dfs(1);
    gospoly();
    ll ans=key[n];
    for(int i=1;d[i];i++)
        if((ans^d[i])>ans)ans^=d[i];
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值