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;
}
posted @ 2017-07-12 17:16  liu_runda  阅读(246)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难