1. 程式人生 > >bzoj - 2115 Xor —— 線性基

bzoj - 2115 Xor —— 線性基

題意:

求圖中從1點到n點的所有路徑中邊權值異或的最大值

思路:

首先要理解,路徑可以任意異或環

像圖中,從1到n的黑色路徑,可以由任意一條紅色路徑到一個環,走遍環之後,再通過紅色路徑回到黑色路徑上,這時紅色路徑上的值被異或了兩次為0,結果就相當於是黑色路徑異或藍色環

環是沒有大小限制的,甚至可以包括黑色路徑,所以通過這種方法可以由任意一條從1到n的路徑得到所有的路徑

剩下的問題一個是求所有環的異或值,可以由一遍深搜得到,每次搜尋下一個點時,若這個點被訪問過,就會形成一個環

另一個問題是求出所有環之後怎麼得到最大的異或值,即從環的異或值中選擇一些數使這些數異或起來最大,線性基

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define max_ 200100
#define mod 1000000007
#define inf 0x3f3f3f3f
struct node
{
    int to;
    ll w;
}zz;
vector< vector<struct node> >v;
int n,m;
ll p[70];
ll value[10000000];
int pl=0;
bool vis[50010];
ll dis[50010];
void dfs(int u)
{
    for(int i=0;i<v[u].size();i++)
    {
        int to=v[u][i].to;
        if(vis[to])
        {
            value[++pl]=dis[u]^dis[to]^v[u][i].w;
        }
        else
        {
            vis[to]=true;
            dis[to]=dis[u]^v[u][i].w;
            dfs(to);
        }
    }
}
void insert(ll n)
{
    for(int i=62;i>=0;i--)
    {
        if((n>>i)&1)
        {
            if(p[i])
            {
                n=n^p[i];
            }
            else
            {
                p[i]=n;
                break;
            }
        }
    }
}
int main(int argc, char const *argv[]) {
    scanf("%d%d",&n,&m);
    v.resize(n+1);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        ll w;
        scanf("%d%d%lld",&x,&y,&w);
        if(x!=y)
        {
            zz.w=w;
            zz.to=x;
            v[y].push_back(zz);
            zz.to=y;
            v[x].push_back(zz);
        }
    }
    dfs(1);
    for(int i=1;i<=pl;i++)
    {
        insert(value[i]);
    }
    ll ans=dis[n];
    for(int i=62;i>=0;i--)
    {
        if((ans^p[i])>ans)
        {
            ans=ans^p[i];
        }
    }
    printf("%lld\n",ans );
    return 0;
}