Xor
给定一个n(n≤50000) 个点m(m≤10000) 条边的无向图,每条边上有一个权值。请你求一条从1到n的路径,使得路径上的边的异或和最大。
线性基
任意选一条道路,作为初始答案
对所有环求异或和
对所有数求线性基,最优解一定是当前道路异或上一些环
贪心修改答案
冗长代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define File(x) "test."#x
#define For(i,s,e) for(int i=(s); i<=(e); i++)
#define Rep(i,s,e) for(int i=(s); i>=(e); i--)
using namespace std;
const int N=50000+15,C=10+5,inf=0x7fffffff;
typedef long long LL;
struct Node{
int x,next; LL w;
}T[N];
int n,m,h[N],len,cnt;
LL ans,cir[N],xs[N];//xor_sum ->xs
bool vis[N];
void addEdge(int x, int y, LL w){
T[++len]=(Node){y,h[x],w}; h[x]=len;
}
void getCircle(int x, int last){
vis[x]=true;
for(int p=h[x]; p; p=T[p].next){
int v=T[p].x;
if(v==last) continue;
if(!vis[v]) xs[v]=xs[x]^T[p].w, getCircle(v, x);
else cir[++cnt]=xs[x] ^ xs[v] ^ T[p].w;
}
}
int main()
{
freopen(File(in),"r",stdin);
freopen(File(out),"w",stdout);
scanf("%d%d",&n,&m);
For(i,1,m){
int u,v;
LL w;
scanf("%d%d%lld",&u,&v,&w);
addEdge(u,v,w); addEdge(v,u,w);
}
getCircle(1, 0);
ans=xs[n];//初始答案
// For(i,1,cnt) printf("%d\n",cir[i]);
sort(cir+1, cir+1+cnt);//应该没啥用
cnt=unique(cir+1, cir+1+cnt)-cir-1;
// printf("%lld\n",ans);
for(int i=63; i>=0; i--){
if(!(ans&(1LL<<i))){//如果这位是 0, 看能否变成 1(这样会更大)
int fp=0;
For(j,1,cnt){
if(cir[j]&(1LL<<i)){
fp=j; break;
}
}
if(!fp) continue;
// printf("%d %d %d\n",i,fp,cir[fp]);
ans^=cir[fp];
For(j,fp+1,cnt){
if(cir[j]&(1LL<<i)) cir[j]^=cir[fp];//make_it_线性基ing
}
cir[fp]=0;
} else {//如果这位是 1,就不能选这位是 1的数(因为这样会让答案变小)
int fp=0;
For(j,1,cnt){
if(cir[j]&(1LL<<i)){
fp=j; break;
}
}
if(!fp) continue;
For(j,fp+1,cnt){
if(cir[j]&(1LL<<i)) cir[j]^=cir[fp];
}
cir[fp]=0;
}
}
printf("%lld\n",ans);
return 0;
}