Trie-字典树-图论
给出一个无根树,每条边有边权,求一条路径,使得这条路径上的边权异或和最大
下面一些关于异或最短路和证明:
与普通最短路不一样的是,这里最短路的距离求的是异或和,而这里的关键就是异或的重要性质:逆反性
首先,随便选一个点当起点,跑一边最短路,求出dis数组,表示点到起点的最短路长度。
当询问点到点的最短路时,分两种情况:
-
点到点的最短路径经过点,那到的最短路就是
dis[x]^dis[y]
-
点到点的最短路径不经过点,如下图:
到的最短路为,的话,可证明出dis[y]=a ^ c
,而这样的话dis[x] ^ dis[y] = a ^ c ^ a = c
所以,点到点的最短路还是dis[x]^dis[y]
上面证明我的博客题解 P5651 【基础最短路练习题】,那题也是求异或和最短路
找出异或的性质后,第一个想到的肯定是的枚举起点和终点。而这个方法,可以转化成对于每一个点,求树中离他最远的点路径长度
我们可以把第二维用Trie来优化
首先,随便找一个点为根,求出所有点距根节点的距离,并把每个点的化为二进制存入
然后,枚举每个点的时候,在中找出:二进制位与当前点尽可能多的不同,并求出最大值
最后将所有输出最大值
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int Maxn=100000+20,inf=0x3f3f3f3f;
struct edge{
int v,len;
edge(int x,int y)
{
v=x,len=y;
}
};
vector <edge> e[Maxn];
int dis[Maxn],g[3100000+233][2];
int n,ans,idcnt=1;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
inline void add(int x)
{
int cur=1;
for(int i=(1<<30);i;i>>=1)
{
bool y=(x & i);
//printf("%d %d %d\n",++cnt,cur,y);
if(!g[cur][y])
{
g[cur][y]=++idcnt;
//printf("%d %d %d\n",cur,idcnt,y);
}
cur=g[cur][y];
}
}
void dfs(int x,int fa)
{
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i].v;
if(y==fa)continue;
dis[y]=dis[x]^e[x][i].len;
dfs(y,x);
}
}
int query(int x)
{
int cur=1,ret=0;
for(int i=(1<<30);i;i>>=1)
{
bool opt=(x & i);
if(g[cur][opt^1])
{
ret+=i;
cur=g[cur][opt^1];
}
else cur=g[cur][opt];
}
return ret;
}
int main()
{
//freopen("in.txt","r",stdin);
n=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read(),c=read();
e[x].push_back(edge(y,c));
e[y].push_back(edge(x,c));
}
dis[1]=0;
dfs(1,0);
for(int i=1;i<=n;++i)
add(dis[i]);
for(int i=1;i<=n;++i)
ans=max(ans,query(dis[i]));
printf("%d\n",ans);
return 0;
}
来源:CSDN
作者:Brian PYL
链接:https://blog.csdn.net/Brian_Pan_/article/details/103594115