BZOJ 2115: [Wc2011] Xor

题面

解题思路

因为异或一个数两次相当于这个数不变,思考可能经过的路径,分为两部分,一部分是简单路径,就是直接到n的路径,还有就是环,如果这个环与简单路径间接相连,我们可以直接把环的贡献异或,因为可以先到环转一圈回去,中间的路径经过两次相当于没经过。考虑到状态比较多,我们考虑线性基,dfs找到环与路径,遇到环插入线性基,最后贪心找最大。

代码

#include<iostream>
#include<cstdio>
#define LL long long

using namespace std;
const int MAXN = 50005;

inline LL rd(){
    LL x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
    return x*f;
}

struct Edge{
    LL nxt,to;
    LL w;
}edge[MAXN<<2];

LL n,m;
int head[MAXN],cnt;
LL ans,b[70],dis[MAXN];
bool vis[MAXN];

inline void add(LL bg,LL ed,LL v){
    edge[++cnt].to=ed;
    edge[cnt].w=v;
    edge[cnt].nxt=head[bg];
    head[bg]=cnt;
}

inline void insert(LL x){
    for(register int i=63;~i;i--)
        if(x&(1ll<<i)){
            if(!b[i]) {b[i]=x;break;}
            else x^=b[i];
        }
}

inline void dfs(int x){
    vis[x]=1;
    for(register LL i=head[x];i;i=edge[i].nxt){
        LL u=edge[i].to;
        if(vis[u]) insert(dis[x]^dis[u]^edge[i].w);
        else dis[u]=dis[x]^edge[i].w,dfs(u);
    }
}

int main(){
    n=rd();m=rd();
    for(register LL i=1;i<=m;i++){
        LL x,y,z;
        x=rd();y=rd();z=rd();
        add(x,y,z);add(y,x,z);
    }
    dfs(1);
    ans=dis[n];
//  cout<<ans<<endl;
    for(register int i=63;i>=0;i--)
        if((ans^b[i])>ans) ans^=b[i];
    printf("%lld",ans);
}
posted @ 2018-07-02 18:18  Monster_Qi  阅读(73)  评论(0编辑  收藏  举报