Bzoj 2115: [Wc2011] Xor

来源:互联网 发布:网络浙江卫视在线直播 编辑:程序博客网 时间:2024/05/23 00:05

原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2115
这里写图片描述
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
Sample Output

6
这里写图片描述

本题因为可以重复走点和边,所以要用异或的性质就是两次异或会抵消。所以本题有个性质就是任何一条路径1~n的异或和都可以当成1~n的一条路径加上若干个环(因为你可以走在路径上,在某一点出发去一个环,在环上走一圈,原路返回,轨迹有了一个环,而且走向环的路径被抵消掉了)。图里环的数量也特别大,把图当成一棵树,每走一条返祖边便统计一个环,假设图边数为m,这样统计到的环是O(m)级别的,有一个性质是图中所有环都可以用这些环异或得到(我不会证,只会意会)。
于是简化问题后,我们有一个数必选,其他有若干个数可以选,最终要取一些数使得异或和最大。这时候要用到一个东西叫线性基。当判断一个二进制是否可以用一堆数异或起来时,可以将这些数简化到logD级别,这里的D表示数的大小。具体方法:从高位到地位每次选一个这位上是1的数,作为一个线性基,将这个数把其他这位上是1的数都异或一遍(有点像高斯消元),最后得到的logD个数便是线性基,这些线性基的最高位各不相同,每次只要从高位到低位把你需要改变的位所对应的线性基异或上去,最后得到的值便是异或的最大值。
之所以WA了好多次是因为当把1左移到int64级别这个1不能直接用1,要么强转,要么定义一个int64类型的存1的变量。否则会有奇怪的运算错误。

type  edge=record         x,y,next:longint;         v:int64;       end;const  MAXN=200050;var  map:array[0..MAXN] of edge;  vis:array[0..MAXN] of boolean;  first:array[0..MAXN] of longint;  path,c:array[0..MAXN] of int64;  x:array[0..63] of int64;  n,m,s,i,a,b,j,k,cnt:longint;  e,v:int64;procedure ins(x,y:longint;v:int64);  begin    inc(s);map[s].x:=x;map[s].y:=y;map[s].v:=v;    map[s].next:=first[x];first[x]:=s;  end;procedure dfs(x:longint);  var    t,y:longint;  begin    vis[x]:=true;    t:=first[x];    while (t>0) do      begin        y:=map[t].y;        if (not vis[y])          then            begin              path[y]:=path[x] xor map[t].v;              dfs(y);            end          else            begin              inc(cnt);              c[cnt]:=path[x] xor map[t].v xor path[y];            end;        t:=map[t].next;      end;  end;begin  read(n,m);  e:=1;  s:=0;  for i:=1 to m do    begin      read(a,b,v);      ins(a,b,v);      ins(b,a,v);    end;  fillchar(vis,sizeof(vis),false);  cnt:=0;  dfs(1);  fillchar(vis,sizeof(vis),false);  for i:=63 downto 0 do    begin      x[i]:=0;      for j:=1 to cnt do        if (not vis[j])and(c[j] and (e << i)>0) then          begin            x[i]:=c[j];vis[j]:=true;            for k:=1 to cnt do              if (not vis[k])and(c[k] and (e << i)>0)                then c[k]:=c[k] xor c[j];            break;          end;    end;  for i:=63 downto 0 do    if (path[n] and (e << i)=0)      then path[n]:=path[n] xor x[i];  writeln(path[n]);end.
0 0
原创粉丝点击