Evanyou Blog 彩带

洛谷P4151 [WC2011] 最大XOR和路径 [线性基,DFS]

  题目传送门

最大XOR和路径

格式难调,题面就不放了。


  分析:

  一道需要深刻理解线性基的题目。

  好久没打过线性基的题了,一开始看到这题还是有点蒙逼的,想了几种方法全被否定了。还是看了大佬的题解才会做的。

  首先我们能想到,在图中从$1$走到$n$有这么两种情况,一种是一条链直接走到$n$,另一种是先走链然后绕若干个环然后回到链上走到$n$。对于这道题显然我们是要考虑所有的环的(由异或的性质可知)。

  然后我们又可以发现,如果一条链和一个环中间有一条路径相连,那么我们从链上走到环上时会经过这条路径一次,从环上回到链上时又会走这条路径一次,那么两次走过的路径异或和就是$0$!

  再看,如果从$1$走到$n$有若干条链,那么这些链会相互构成若干个环,如果我们走了一条链,然后让这条链异或这些环,就可以得到对应的另一条链!(可以自己画图分析一下,博主太懒不想画图_(:з」∠)_)

  综合一下上面的性质,我们就能得到一种算法:进行一遍$DFS$,把所有的环构造成线性基,然后把任意一条从$1$到$n$的链放入线性基中求最大异或和。

  $SO$,这道黑题就这么过了。

  博主手残写了个$namespace$,不过好像跑得还挺快。

  Code:

 

//It is made by HolseLee on 3rd Sep 2018
//Luogu.org P4151
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;

typedef long long ll;
const int N=5e4+7,M=2e5+7;;
int n,m,head[N],cnte;
ll dis[N],b[70];
bool vis[N];
struct Node {
    int to,nxt; ll val;
    
    Node() {}
    Node(int _to,ll _val,int _nxt): to(_to),val(_val),nxt(_nxt) {}
}e[M];

namespace LinerBase {
    void insert(ll x)
    {
        for(int i=63; i>=0; --i) {
            if( !(x>>i) ) continue;
            if( !b[i] ) {
                b[i]=x; break;
            } else {
                x^=b[i];
            }
        }
    }

    ll quary(ll x)
    {
        ll ret=x;
        for(int i=63; i>=0; --i) {
            if( (ret^b[i])>ret ) ret^=b[i];
        }
        return ret;
    }
}

inline ll read()
{
    char ch=getchar(); ll num=0; bool flag=false;
    while( ch<'0' || ch>'9' ) {
        if( ch=='-' ) flag=true;
        ch=getchar();
    }
    while( ch>='0' && ch<='9' ) {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return flag ? -num : num;
}

inline void add(int x,int y,ll z)
{
    e[++cnte]=Node(y,z,head[x]);
    head[x]=cnte;
}

void dfs(int x,ll now)
{
    dis[x]=now, vis[x]=true;
    for(int i=head[x]; i; i=e[i].nxt) {
        if(!vis[e[i].to]) dfs(e[i].to,now^e[i].val);
        else LinerBase::insert(now^e[i].val^dis[e[i].to]);
    }
}

int main()
{
    n=read(); m=read();
    int x,y;ll z;
    for(int i=1; i<=m; ++i) {
        x=read(), y=read(), z=read();
        add(x,y,z); add(y,x,z);
    }
    dfs(1,0);
    printf("%lld\n",LinerBase::quary(dis[n]));
    return 0;
}

 

 

 

posted @ 2018-09-03 19:39  HolseLee  阅读(300)  评论(0编辑  收藏  举报