Code[vs]1187 Xor最大路径

Description

问题概括:求一棵带边权的树的一条最大Xor路径的值。

Input Description

第一行,一个整数N,表示一颗树有N个节点,接下来N-1行,每行三个整数a,b,c表示节点a和节点b之间有条权值为c的边

Output Description

输出仅一行,即所求的最大值

Sample Input

4

1 2 3

1 3 4

1 4 7

Sample Output

7

Data Size & Hint

【数据规模】

对于40%的数据,数据退化为一条链

除上述的40%的数据外,还有10%的数据N<=1000

100%的数据满足2<=n<=100000,1

Solution

让我们求异或和的最大值,显然可以想到用trie来贪心。
任选一个点作为根节点,然后求出每一个点都根的距离,那么任意一条路径的异或和就是两个端点到根的距离的异或和。(画个图想一想,即便这个路径不经过根也是如此)
然后每次枚举一下,若是当前位是1,就找trie树上有没有为0的节点,没有的话再找为1的节点。这样按位贪心一下即可。

这道题和code[vs]的3031完全是一道题,可是3031是黄金题,这道题是master……

Code(Pascal)

uses math;
type new=record
  l:int64; r:int64;
end;
var  n,tot,rt,t,cnt:int64;  i,j:longint;
     x,y,z,q,s,ans,k:int64;
     dis:array [0..100005] of int64;
     next,head,fa:array [0..200050] of int64;
     b:array [0..200050] of new;
     a:array [0..45] of int64;
     tr:array [0..5000000,0..1] of longint;
procedure add(x,y,z:int64);
begin
  inc(tot);
  next[tot]:=head[x];
  head[x]:=tot;
  b[tot].l:=y;
  b[tot].r:=z;
end;
procedure dfs(x:longint);
var   i,j:longint;
begin
  i:=head[x];
  while i<>0 do begin
    j:=b[i].l;
    if j<>fa[x] then begin
      dis[j]:=dis[x] xor b[i].r;
      fa[j]:=x;
      dfs(j);
    end;
    i:=next[i];
  end;
end;
procedure turn(x:int64);
var i,l:longint;
begin
  l:=0;
  while x<>0 do begin
    inc(l);
    a[l]:=x mod 2;
    x:=x shr 1;
  end;
  for i:=l+1 to 40 do a[i]:=0;
end;
begin
  readln(n);
  for i:=1 to n-1 do begin
    read(x,y,z);
    add(x,y,z);
    add(y,x,z);
  end;
  fa[1]:=1;
  dfs(1);
  for i:=1 to n do begin
    rt:=0;
    turn(dis[i]);
    for j:=40 downto 1 do begin
      t:=a[j];
      if tr[rt,t]=0 then begin
        inc(cnt);
        tr[rt,t]:=cnt;
      end;
      rt:=tr[rt,t];
    end;
  end;
  q:=1;
  for i:=1 to 39 do q:=q*2;
  for i:=1 to n do begin
    rt:=0;
    s:=q;
    k:=0;
    turn(dis[i]);
    for j:=40 downto 1 do begin
      t:=a[j] xor 1;
      if tr[rt,t]<>0 then begin
         k:=k+s;
         rt:=tr[rt,t];
      end else rt:=tr[rt,t xor 1];
      s:=s shr 1;
    end;
    ans:=max(ans,k);
  end;
  writeln(ans);
end.

代码不是很简洁但是很好理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值