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.
代码不是很简洁但是很好理解。