2115: [Wc2011] Xor
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2142 Solved: 893
[Submit][Status][Discuss]
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
Source
Solution
线性基
思路就是先随意一条路径,然后把每个环的存下来,求线性基,再与之前的路径取xor,取最大即为答案
至于线性基,它的意义是:通过原集合S的某一个最小子集S1使得S1内元素相互异或得到的值域与原集合S相互异或得到的值域相同。
然后XJB乱搞一下,具体写的比较明白的还是Oxer 折越
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; long long read() { long long 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; } #define maxn 500010 #define maxm 5000010 int n,m,num; struct EdgeNode{int next,to;long long val;}edge[maxm<<1]; int head[maxn],cnt; void add(int u,int v,long long w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;} void insert(int u,int v,long long w) {add(u,v,w); add(v,u,w);} bool visit[maxn];long long val[maxn],a[maxn]; void DFS(int now) { visit[now]=1; for (int i=head[now]; i; i=edge[i].next) if (!visit[edge[i].to]) val[edge[i].to]=val[now]^edge[i].val,DFS(edge[i].to); else a[++num]=val[edge[i].to]^edge[i].val^val[now]; } int Gauss() { int tmp=1; for (int p=64; p>=0; p--) { int t=0; for (int j=tmp; j<=num; j++) if ((a[j]>>p)&1) {t=j;break;} if (t) { swap(a[t],a[tmp]); for (int j=1; j<=num; j++) if (j!=tmp && ((a[j]>>p)&1)) a[j]^=a[tmp]; tmp++; } } return tmp-1; } int main() { n=read(); m=read(); for (int u,v,i=1; i<=m; i++) u=read(),v=read(),insert(u,v,read()); DFS(1); long long ans=val[n]; num=Gauss(); for (int i=1; i<=num; i++) ans=max(ans,ans^a[i]); printf("%lld ",ans); return 0; }
hsy大爷发题不写题解,程序还是hzwer的翻版