bzoj2115[WC2011]Xor
题意
选出一条从1到n的路径(可以不是简单路径),使得其上边权异或和最大.
分析
快退役了,抓紧涨一下bzoj题量.
任意找出一条从1到n的路径,另外一条从1到n的路径一定可以表示成这条路径异或上若干个环.所以dfs找出所有dfs树上反向边,跑线性基,贪心求最大值即可.
那么这篇题解主要是记录一下自己的脑残...我的写法把每个环算了两次,意识到这点后我这样想:既然是连通图,dfs树上有n-1条树边,m-(n-1)条非树边,极限数据点数50000,边数100000,有100000-(50000-1)=50001条非树边,一条边算两次,那么开100005的数组也完全够了.然后RuntimeError根本停不下来...
实际上是这样:边数取到100000时,点数可以不取到50000,这样极限情况下我大约需要200000多一点的数组...
怎么还有这种RuntimeError
#include<cstdio>
#include<cstring>
typedef unsigned long long ul;
const int maxn=50005,maxm=100005;
struct edge{
int to,next;ul w;
}lst[maxm<<1];int len=0,first[maxn];
void addedge(int a,int b,ul w){
lst[len].to=b;lst[len].next=first[a];lst[len].w=w;first[a]=len++;
}
bool vis[maxn];
ul w[maxm];
ul cir[maxm<<1];
int tot=0;
int prt[maxn],dfn[maxn];
void dfs(int x){
vis[x]=true;
for(int pt=first[x];pt!=-1;pt=lst[pt].next){
if(!vis[lst[pt].to]){
w[lst[pt].to]=w[x]^lst[pt].w;
prt[lst[pt].to]=pt;
dfs(lst[pt].to);
}else if(pt!=(prt[x]^1)){
cir[++tot]=w[lst[pt].to]^w[x]^lst[pt].w;
}
}
}
ul b[70];
void getbase(){
ul* a=cir;
for(int i=1;i<=tot;++i){
for(int j=60;j>=0;--j){
if(a[i]>>j&1){
if(b[j])a[i]^=b[j];
else{
b[j]=a[i];
for(int k=j-1;k>=0;--k)if(b[k]&&(b[j]>>k&1))b[j]^=b[k];
for(int k=j+1;k<=60;++k)if(b[k]>>j&1)b[k]^=b[j];
break;
}
}
}
}
}
int main(){
memset(first,-1,sizeof(first));
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
int a,b;ul w;
scanf("%d%d%llu",&a,&b,&w);
if(a==b)cir[++tot]=w;
else{
addedge(a,b,w);
addedge(b,a,w);
}
}
dfs(1);
getbase();
for(int j=60;j>=0;--j){
if(b[j]&&(!(w[n]>>j&1)))w[n]^=b[j];
}
printf("%llu\n",w[n]);
return 0;
}