链接:POJ - 3764 The xor-longest Path
题意:
给出一棵 n ( 1 ≤ n ≤ 100000 ) n(1\le n\le100000) n(1≤n≤100000)个结点的树,每条边具有边权 w ( 0 ≤ w ≤ 2 31 ) w(0\le w\le 2^{31}) w(0≤w≤231),结点编号从 0 0 0到 n − 1 n-1 n−1。要求求出 异或和最大的路径(即路径上所有边权 w w w异或和最大),所有结点均可作为起点、终点。
分析:
由于异或的性质,其实只需要 任选一点作为根结点,如上图的
A
A
A,然后 DFS算得所有其他点到A点的异或和
s
u
m
A
−
X
sum_{A-X}
sumA−X 即可。
那么则有,任意两个点路径上的异或和 s u m X − Y = s u m A − X ⊕ s u m A − Y sum_{X-Y}=sum_{A-X}\oplus sum_{A-Y} sumX−Y=sumA−X⊕sumA−Y
因为异或时,相同部分的路径边权
w
w
w相同,异或得
0
0
0,不相同部分相互异或,最后与
0
0
0异或,不变。
例如 求 F F F到 J J J路径上的边权异或和 s u m F − J sum_{F-J} sumF−J
s u m A − F = w A − C ⊕ w C − F sum_{A-F}=w_{A-C}\oplus w_{C-F} sumA−F=wA−C⊕wC−F
s u m A − J = w A − C ⊕ w C − E ⊕ w E − J sum_{A-J}=w_{A-C}\oplus w_{C-E}\oplus w_{E-J} sumA−J=wA−C⊕wC−E⊕wE−J
   ⟹    s u m A − F ⊕ s u m A − J = ( w A − C ⊕ w C − F ) ⊕ ( w A − C ⊕ w C − E ⊕ w E − J ) \implies sum_{A-F}\oplus sum_{A-J}=(w_{A-C}\oplus w_{C-F})\oplus (w_{A-C}\oplus w_{C-E}\oplus w_{E-J}) ⟹sumA−F⊕sumA−J=(wA−C⊕wC−F)⊕(wA−C⊕wC−E⊕wE−J)
= ( w A − C ⊕ w A − C ) ⊕ ( w C − F ⊕ w C − E ⊕ w E − J ) = 0 ⊕ ( w C − F ⊕ w C − E ⊕ w E − J ) = (w_{A-C}\oplus w_{A-C})\oplus(w_{C-F}\oplus w_{C-E}\oplus w_{E-J})=0\oplus(w_{C-F}\oplus w_{C-E}\oplus w_{E-J}) =(wA−C⊕wA−C)⊕(wC−F⊕wC−E⊕wE−J)=0⊕(wC−F⊕wC−E⊕wE−J)
= w C − F ⊕ w C − E ⊕ w E − J = s u m F − J =w_{C-F}\oplus w_{C-E}\oplus w_{E-J}=sum_{F-J} =wC−F⊕wC−E⊕wE−J=sumF−J
综上,该题只需要DFS一次,每次遍历到一个结点X就先在01字典树中找到与 s u m A − X sum_{A-X} sumA−X异或最大的,然后把 s u m A − X sum_{A-X} sumA−X放入01字典树中即可。
以下代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+50;
const int max_base=31;
int n;
struct edge
{
int u;
int v;
int w;
int next;
}e[maxn<<1];
int head[maxn],s,cnt;
void addedge(int u,int v,int w)
{
e[cnt]=edge{u,v,w,head[u]};
head[u]=cnt++;
e[cnt]=edge{v,u,w,head[v]};
head[v]=cnt++;
}
int ch[31*maxn][2],val[31*maxn],tot;
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
tot=1;
ch[0][0]=ch[0][1]=0;
val[0]=0;
}
void ins(int x)
{
int u=0;
for(int i=max_base;i>=0;i--)
{
int cur=(x>>i)&1;
if(!ch[u][cur])
{
ch[tot][0]=ch[tot][1]=0;
val[tot]=0;
ch[u][cur]=tot++;
}
u=ch[u][cur];
}
val[u]=x;
}
int query_max(int x)
{
int u=0;
for(int i=max_base;i>=0;i--)
{
int cur=(x>>i)&1;
if(ch[u][cur^1])
u=ch[u][cur^1];
else
u=ch[u][cur];
}
return x^val[u];
}
int ans;
void dfs(int u,int pre,int sum)
{
ans=max(ans,query_max(sum));
ins(sum);
for(int i=head[u];i!=-1;i=e[i].next)
{
if(e[i].v!=pre)
dfs(e[i].v,u,sum^e[i].w);
}
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=1;i<=n-1;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
}
ans=0;
dfs(0,-1,0);
printf("%d\n",ans);
}
return 0;
}