bzoj2115 [Wc2011] Xor
Description
Input
第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。
Output
仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。
Sample Input
5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
Sample Output
6
HINT
正解:线性基。
又是一道鬼畜的线性基神题。。这是我做的第二道WC的题,也可能将会是我做的代码量最短的WC题。。
我们考虑如何得到答案,首先所有的环都是可以经过的。这是为什么呢?
假设我们从1号点开始走,走到一个环的起点,然后我们经过这个环以后回到了环的起点,这时我们可以直接回到起点。这样,除了环上的路径,其他的路径都被抵消了。那么我们就只选了了这个环,也就是说,任意一个环都是可以选的。
然后我们先把所有的环都选出来,选入线性基中,再选出任意一条从1到n的路径,作为初始ans。初始ans异或线性基的最大值就是我们求的答案。为什么任意选一条路径也是可行的呢?
我们选了一条路径以后,如果存在一条更优的路径,那么这两条路径肯定是构成一个环的,会被选入线性基中。那么我们再用初始的ans异或一下这个环,我们就会发现,初始的ans被抵消了,二更优的那条路径留了下来。所以,我们选一个任意的初始ans是可行的。
于是这道题的实现就很明显了。先找出所有环,构成线性基,然后找出初始ans。这两步显然是可以dfs一遍一起搞的。然后用ans去异或线性基。从高位开始往低位异或。如果当前ans异或这一位的数能使ans变大,那么就异或。最终得到的ans就是我们要求的答案。
所以根据这题,我们还可以得到一个结论:任意一条1到n的路径的异或和,都可以由任意一条1到n的路径的异或和和一些环的异或和来组合得到。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define M (100010) 16 #define N (50010) 17 #define il inline 18 #define RG register 19 #define ll long long 20 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 21 22 using namespace std; 23 24 struct edge{ ll nt,to,dis; }g[2*M]; 25 26 ll a[4*M],head[N],vis[N],d[N],p[65],n,m,num,cnt,ans; 27 28 il ll gi(){ 29 RG ll x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 30 if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; 31 } 32 33 il void insert(RG ll from,RG ll to,RG ll dis){ g[++num]=(edge){head[from],to,dis},head[from]=num; return; } 34 35 il void dfs(RG ll x){ 36 vis[x]=1; 37 for (RG ll i=head[x],v=g[i].to;i;i=g[i].nt,v=g[i].to){ 38 if (!vis[v]) d[v]=d[x]^g[i].dis,dfs(v); 39 else a[++cnt]=d[v]^d[x]^g[i].dis; 40 } 41 return; 42 } 43 44 il void add(RG ll x){ 45 for (RG ll i=62;i>=0;--i) 46 if (x>>i&1){ 47 if (!p[i]){ p[i]=x; break; } 48 x^=p[i]; 49 } 50 return; 51 } 52 53 il ll getmax(RG ll x){ RG ll res=x; for (RG ll i=62;i>=0;--i) if (res<(res^p[i])) res^=p[i]; return res; } 54 55 il void work(){ 56 n=gi(),m=gi(); for (RG ll i=1,u,v,w;i<=m;++i) u=gi(),v=gi(),w=gi(),insert(u,v,w),insert(v,u,w); 57 dfs(1); for (RG ll i=1;i<=cnt;++i) add(a[i]); ans=getmax(d[n]); printf("%lld\n",ans); return; 58 } 59 60 int main(){ 61 File("xor"); 62 work(); 63 return 0; 64 }