链接
http://poj.org/problem?id=3764
大意
给定
个点和
条无向边
设一种运算
,表示从
到
的路径长度的异或值,求出最大的
思路
设 表示根节点到 的路径上所有边权的 值,设 为 的子节点,显然有
所以我们可以先用一个
或者
(本人用的是
)求出所有的
,然后通过发现
到
的路径的异或值就等于
,这是因为根据
的性质,
,
到根和
到跟这两条路径重叠的部分恰好被抵消掉
所以,问题就变成了从
数组中任选两个数,使得它们的异或值最大,即为CH 1602 The XOR Largest Pair
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int trie[3500001][2],tot,n,l[200001],cnt,x,y;
long long d[200001],ans,w;
struct node
{
int next,to;long long w;
}e[200001];
inline void add(register int x,register int y,register long long w)//建边
{
e[++cnt]=(node){l[x],y,w};l[x]=cnt;
return;
}
inline void bfs(register int st)//求d
{
queue<int>q;q.push(st);
bool vis[1000001]={0};vis[st]=true;
while(q.size())
{
int x=q.front();q.pop();vis[x]=true;
for(register int i=l[x];~i;i=e[i].next)
{
int y=e[i].to,w=e[i].w;
if(!vis[y])
{
q.push(y);
d[y]=d[x]^w;
}
}
}
return;
}
inline void insert(register long long x)//插入
{
int p=0;
for(register int k=31;k>=0;k--)
{
int id=(x>>k)&1;
if(!trie[p][id]) trie[p][id]=++tot;
p=trie[p][id];
}
return;
}
inline long long search(register long long x)//查找
{
int p=0;
long long ans=0;
for(register int k=31;k>=0;k--)
{
int id=(x>>k)&1,o=id^1;
if(trie[p][o]) {p=trie[p][o];ans=ans<<1|1;}
else if(trie[p][id]) {p=trie[p][id];ans<<=1;}
}
return ans;
}
signed main()
{
while (~scanf("%d",&n))
{
tot=0;cnt=0;
memset(l,-1,sizeof(l));
memset(trie,0,sizeof(trie));ans=0;
memset(d,0,sizeof(d));//初始化
for(register int i=1;i<n;i++)
{
scanf("%d%d%lld",&x,&y,&w);
x++;y++;
add(x,y,w);add(y,x,w);//无向边
}
bfs(1);//计算d
for(register int i=1;i<=n;i++)
{
ans=max(ans,search(d[i]));
insert(d[i]);
}
printf("%lld\n",ans);//输出
}
}