Bzoj2110--Wc2011Xor

考虑如果我们已经到达了终点,那么从终点出发显然可以异或上图中任何地方一个环的异或值后再回到终点,那么我们显然可以在到达终点后根据环的异或值调整自己

所以我们可以先处理出环上的异或值,我的做法是先做一颗生成树,然后dfs确定每个点到根的异或值再加入非树边,这时每条非树边都对应一个环,其他复杂环都可以由这些环互相异或得到。处理下线性基在贪心选取。

有个小细节是树边上1到n的路径是必须选的,所以要基于这条路径贪心。

代码:

#include<bits/stdc++.h>
#define INF 1000000000
#define LNF 100000000000000ll
#define eps 1e-12
#define LL long long
inline int _max(int a,int b) {return a>b?a:b;}
inline long double _fabs(long double a) {return a>0?a:-a;}

using namespace std;
#define MAXN 50005
#define MAXM 100005

int n,m,x[MAXN],fr[MAXM],to[MAXM],tot;
LL gs[MAXN],cs[MAXM],ans;bool f[MAXM];

int fa(int v) {
    int k=v,b=v;
    while(x[v]!=v) v=x[v];
    while(x[k]!=v) {
        x[k]=v;k=x[b];b=k;
    }
    return v;
}

int head[MAXN],cnt;
struct Edge{
    int to,next;LL w;
}e[MAXM];
void insert(int a,int b,LL c) {
    e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;e[cnt].w=c;
    e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;e[cnt].w=c;
}

LL xr[MAXN];bool vis[MAXN];
void dfs(int v,LL k) {
    xr[v]=k;vis[v]=1;
    for(int i=head[v];i;i=e[i].next) 
        if(!vis[e[i].to]) 
            dfs(e[i].to,k^e[i].w);
}

LL num[72];
void Gauss() {
    for(int i=1;i<=tot;i++) 
        for(int j=62;j>=0;j--) if(gs[i]>>j&1) {
            if(num[j]) gs[i]^=num[j];else {num[j]=gs[i];break;}
        }
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) x[i]=i;
    for(int a,b,i=1;i<=m;i++) {
        scanf("%d%d%lld",&fr[i],&to[i],&cs[i]);
        a=fa(fr[i]);b=fa(to[i]);
        if(a!=b) x[a]=b,insert(fr[i],to[i],cs[i]),f[i]=1;
    }
    dfs(n,0);
    for(int i=1;i<=m;i++) if(!f[i]) gs[++tot]=xr[fr[i]]^xr[to[i]]^cs[i];
    Gauss();
    ans=xr[1];
    for(int i=62;i>=0;i--) 
        if((ans^num[i])>ans) ans=ans^num[i];
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/ihopenot/p/5952910.html