P4551-最长异或路径
题意:
在有点权的树上找一条链,使得链上所有点异或和最大。
思路:
- 在树上的异或有这样的性质:两个节点的链的异或和等于两个点分别到根结点的异或和的异或和。于是考虑预处理出所有点到根结点的异或和前缀,作为新的点权。则原问题转化为在所有点中找两个使得其异或和最大。
- 这是个经典问题,解法:把所有数扔进\(Trie\)树里,\(Trie\)树上每个节点维护经过了多少个数,枚举所有数,若当前位为\(0/1\)则优先向\(1/0\)查看有没有数经过,跑到最后一位可以找出一个数来更新答案。复杂度\(O(nlogn)\)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const ll inf=1e15;
const int maxm=5e5+10;
int n,m;
struct node{
int v;int w;
};
vector<node> yuan[maxn];
int zhi[maxn];
void dfs(int now,int fa,int xo){
zhi[now]=xo;
for(int i=0;i<yuan[now].size();i++){
int v=yuan[now][i].v,w1=yuan[now][i].w;
if(v==fa) continue;
dfs(v,now,(xo^w1));
}
}
struct trie{
int cha[2];
}all[maxn<<4];
int tot;
void build(int now,int x){
for(int i=(1LL<<33);i>0;i>>=1LL){
int c1=((now&i)?1:0);
if(!all[x].cha[c1]) all[x].cha[c1]=++tot;
x=all[x].cha[c1];
}
}
ll req(int now,int x){
ll ans1=0;
for(int i=(1LL<<33);i>0;i>>=1LL){
int c1=((now&i)?1:0);
if(all[x].cha[!c1]){
ans1+=i;
x=all[x].cha[!c1];
}
else x=all[x].cha[c1];
}
return ans1;
}
signed main(){
cin>>n;
for(int i=1;i<n;i++){
int u,v,w;cin>>u>>v>>w;
yuan[u].push_back((node){v,w});
yuan[v].push_back((node){u,w});
}
dfs(1,0,0);
for(int i=1;i<=n;i++) build(zhi[i],0);
ll ans=0;
for(int i=1;i<=n;i++) ans=max(ans,req(zhi[i],0));
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号