题意: 题目说的很抽象,需要提炼:先将图中所有环的异或和求出为val,再从中取出若干val(不同环的),求最大的异或和。(保证是连通图)
1、 求环的异或和值,用图的DFS遍历来搜索出结果;需要辅助数组vis[i],
vis[u]==0标注节点u已经遍历完成,vis==1标注已经遍历,但未完全,仍在
遍历其后代,显然我们遍历到当前v与u连边 (vis[u]=1且u不为v的父节点),
则u是v的祖先(至少爷爷辈),且u到v的路径(一路v的祖先)+v->u成环。
此即为我们要求的其中一个环,计算其边的Xor和,我们仅需要将
记F[u]为u到root路径上边值异或和
环的异或和: F[u]^F[v]^(Value[v-u])//F[u]重复两次,异或抵消,就变成了间接u到v的边异或和。
2、每次求出一个环的Xor和,将其添入,更新此线性基。
3、 最后将所有基值A[i] 异或,求出其和即为ans。
花时:1981ms。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#define llt long long
using namespace std;
const int Size=5*1e4+10;
struct node_t{
int to,nxt;
llt val;
}p[Size*4];
int head[Size],vis[Size];
llt A[65],pow_2[65];
llt F[Size];//记录节点i到rt路径上边值的异或和
int N,M;
int toUsed=1;
void mkEdge(int u,int v,llt val){
p[toUsed].to=v;
p[toUsed].nxt=head[u];
p[toUsed].val=val;
head[u]=toUsed++;
p[toUsed].to=u;
p[toUsed].nxt=head[v];
p[toUsed].val=val;
head[v]=toUsed++;
}
void init(){
toUsed=1;
memset(head,0,sizeof(head));
memset(vis,-1,sizeof(vis));
memset(A,0,sizeof(A));
}
//vis==0 遍历完成
//vis==1 遍历开始但未完成
void add_BaseLine(llt x){
int i;
for(i=59;i>=0;i--)
if(x&(1ll<<i)){
if(A[i]){x^=A[i];}
else {
for(int j=i-1;j>=0;j--)
if(x&(1ll<<j)) x^=A[j];
A[i]=x;
for(int j=i+1;j<60;++j)
if(A[j]&(1ll<<i)) A[j]^=x;
return;
}
}
}
llt Query_Max(){
llt ans=0;
for(int i=0;i<60;++i)ans^=A[i];
return ans;
}
void DFS_MAP(int rt,int fa){
vis[rt]=1;
for(int i=head[rt];i;i=p[i].nxt){
int to=p[i].to;
if(fa==to||vis[to]==0) continue;
if(vis[to]==1) {
add_BaseLine(F[rt]^F[to]^p[i].val);continue;}
F[to]=F[rt]^p[i].val;
DFS_MAP(to,rt);
}
vis[rt]=0;
}
int main(){
int T,kase=0;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&N,&M);
while(M--){
int u,v;
llt val;
scanf("%d%d%lld",&u,&v,&val);
mkEdge(u,v,val);
}
F[1]=0;
DFS_MAP(1,0);
printf("Case #%d: %lld\n",++kase,Query_Max());
}
return 0;
}