最长异或路径java_【维护异或极值】 最长异或路径

题意

给定一棵树,树上的边都有权值,树上的一条异或路径长度定义为两点间路径上所有边的异或和

\(\operatorname{xor} \operatorname{length}(p)=\oplus_{e \in p} w(e)\)

给定上述的具有\(n\)个节点的树,求最大的异或和路径的值

数据范围

\(\begin{array}{l}1 \leq n \leq 100000 \\ 0 \leq u, v

题解

维护每个节点从根到它路径的异或和,求任意两点的路径直接异或两个点到根的异或和即可

\(dfs\)求出每个节点到根的异或和,三个状态当前节点、上一节点、当前异或和

树是无向的,所以要判断一下下一个点是不是等于上一个点

异或运算的计算顺序不影响结果

如果两个节点从\(LCA\)开始的公共路径的异或值相同,异或和为\(0\),相当于不异或

所以求任意两点间就用字典树维护所有点到根的距离,贪心的从高位开始选择,优先选择高位不同的,

即高位异或后可以得到的值

Code

#include

using namespace std;

#define rep(i,a,n) for(int i=a;i

#define per(i,a,n) for(int i=n-1;i>=a;i--)

const int N=1e5+10;

int n;

struct node

{

int to,ne,w;

}e[N*2];

int h[N],id;

int d[N];

int trie[N*30][2],tot=1;

void add(int u,int v,int w)

{

e[++id].to = v;

e[id].w=w;

e[id].ne=h[u];

h[u]=id;

}

void insert(int x)

{

int p=1;

per(i,0,31)

{

int c = x>>i&1;

if(!trie[p][c]) trie[p][c]=++tot;

p=trie[p][c];

}

}

int query(int x)

{

int res=0;

int p=1;

per(i,0,31)

{

int c=x>>i&1;

if(trie[p][!c])

{

res+=1<

p=trie[p][!c];

}

else p=trie[p][c];

}

return res;

}

void dfs(int u,int pre,int sum)

{

d[u]=sum;

for(int i=h[u];i;i=e[i].ne)

if(e[i].to!=pre) dfs(e[i].to,u,sum^e[i].w);

}

void solve()

{

int ans=-1e9;

cin>>n;

rep(i,0,n)

{

int u,v,w;

cin>>u>>v>>w;

add(u,v,w);add(v,u,w);

}

dfs(0,-1,0);

rep(i,0,n)

{

insert(d[i]);

ans=max(ans,query(d[i]));

}

cout<

}

int main()

{

solve();

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值