最长异或路径

题目链接

戳我

前置知识

  1. 什么是异或?
  • 如果二进制下同一位不相同,则为一,否则为0
    \[eg:(3)_{10}\ xor \ (2)_{10}=(11)_2\ xor\ (10)_2=(01)_2=1 \]
  1. tire树

  2. 基本位运算

对于同一条边异或两次,相当于没有进行异或,我们将dis[i]表示为从i点到根节点的路径异或和。则问题转化为了求两点的dis异或最大值

我们可以根据dis构建一颗01 tire树(自行百度)

贪心的想,对于一个数X,我们对于dis[i]^x最大,则每次往x相反的值选。
及如果x这一位是1,我们在tire树上往0跑,反之往1跑。这样的一定是最大的。

code

#include<bits/stdc++.h>
#define int ll
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
typedef long long ll;
const int N=1000010;
int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
int dis[N],head[N],cnt,tot=1;
struct node {
    int to,next,v;
}b[N<<1];
void dfs(int x,int fa){
    for(int i=head[x];i;i=b[i].next){
        int v=b[i].to;
        if(v==fa)
            continue;
        dis[v]=dis[x]^b[i].v;       
        dfs(v,x);
    }
}
void add(int x,int y,int v){
    b[++cnt].to=y;
    b[cnt].next=head[x];
    b[cnt].v=v;
    head[x]=cnt;
}
struct node1 {
    int ch[2];
}a[N<<2];
void build(int x){
    int u=1;
    for(int i=32;i>=0;i--){
        int c=(x>>i)&1;
        if(!a[u].ch[c])
            a[u].ch[c]=++tot;
        u=a[u].ch[c];
    }
}
int find(int x){
    int u=1,ans=0;
    for(int i=32;i>=0;i--){
        int c=((x>>i)&1)^1;
        if(a[u].ch[c])
            u=a[u].ch[c],ans+=1<<i;
        else
            u=a[u].ch[c^1];
    }
    return ans;
}
 main(){
    int n=read(),x,y,z,ans=0;
    for(int i=1;i<n;i++)
        x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
    dfs(1,0);
    for(int i=1;i<=n;i++)
        build(dis[i]);
    for(int i=1;i<=n;i++)
        ans=max(ans,find(dis[i]));
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hbxblog/p/10167136.html