字符串训练三
https://www.luogu.org/problem/P4551
题目描述:
给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或
分析:
嗯?这不是个图论题吗?什么狗屁字符串?
首先看到异或,那01trie树就必不可少的了
首先对一条边异或2次,相当于没有异或。
这样的话 i -> j 的异或和,就是 i -> 1 的异或和,再异或上 1 -> j 的异或和。
处理出每个点到1路径的异或和,然后找两个,使它们异或起来最大。
等等这不又是板子题吗?
找出两个异或最大(这个我前面两个练习有说)
于是直接套板子即可
code by wzxbeliever
#include<bits/stdc++.h>
#define ll long long
#define ri register int
#define il inline
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=100005;
int head[maxn],tr[maxn*31][2],w[maxn];
int n,ans,rt,cnt,tot;
struct node{int to,next,w;}edg[maxn<<1];
il void add(int u,int v,int w){++cnt;edg[cnt].next=head[u];edg[cnt].w=w;edg[cnt].to=v;head[u]=cnt;}
il void bulid(int x,int rt){
for(ri i=1<<30;i;i>>=1){bool c=x&i;
if(!tr[rt][c])tr[rt][c]=++tot;
rt=tr[rt][c];
}
}
il int query(int x,int rt){
int ans=0;
for(ri i=1<<30;i;i>>=1){bool c=x&i;
if(tr[rt][c^1])ans+=i,rt=tr[rt][c^1];
else rt=tr[rt][c];
}return ans;
}
il void dfs(int u,int fa){
for(ri i=head[u];i;i=edg[i].next){int to=edg[i].to;
if(to==fa)continue;
w[to]=w[u]^edg[i].w;dfs(to,u);
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%d",&n);
for(ri i=1,u,v,w;i<n;i++)scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
dfs(1,0);
for(ri i=1;i<=n;i++)bulid(w[i],rt);
for(ri i=1;i<=n;i++)ans=max(ans,query(w[i],rt));
printf("%d
",ans);
return 0;
}