BZOJ 2115 [Wc2011] Xor ——线性基

【题目分析】

    显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可。

    但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有的简单环都可以经过各种各样的异或得到。

    然后线性基,在从高位向低位贪心即可,至于证明,需要拟阵的相关知识。

【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
 
#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
 
#define maxn 100005
#define ll long long
 
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
 
int h[maxn],to[maxn<<1],ne[maxn<<1];
ll w[maxn<<1];
int en=0,n,m,vis[maxn],tot=0;
ll a[maxn<<1];
ll dis[maxn];
 
void add(int a,int b,ll c)
{
    to[en]=b;
    w[en]=c;
    ne[en]=h[a];
    h[a]=en++;
}
 
void dfs(int k)
{
//  printf("dfs on %d\n",k);
    vis[k]=1;
    for (int i=h[k];i>=0;i=ne[i])
    {
        if (!vis[to[i]])
        {
            dis[to[i]]=dis[k]^w[i];
            dfs(to[i]);
        }
        else a[++tot]=dis[k]^dis[to[i]]^w[i];
    }
}
 
ll lb[64],ans;
 
int main()
{
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;++i)
    {
        int a,b; ll c;
        scanf("%d%d%lld",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    dfs(1);
    ans=dis[n];
//  for (int i=1;i<=n;++i) cout<<dis[i]<<" "; cout<<endl;
//  for (int i=1;i<=tot;++i) cout<<a[i]<<" ";cout<<endl;
    for (int i=1;i<=tot;++i)
    {
        for (int j=63;j>=0;j--)
        {
            if ((a[i]>>j)&1){
                if (!lb[j]) {lb[j]=a[i];break;}
                else a[i]^=lb[j];
            }
        }
    }
    for (int i=63;i>=0;i--)
        if (lb[i]&&((ans>>i)&1)==0) ans^=lb[i];
    cout<<ans<<endl;
    return 0;
}

  

posted @ 2016-12-20 23:19  SfailSth  阅读(128)  评论(0编辑  收藏  举报