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; }