P4551 最长异或路径 题解

淦,异或的性质必须要熟悉啊!!!不看题解就想不到,一看题解就啥都会了)

一个完美的性质:$a\oplus b\oplus b=a$

 于是,对于一个路径$d(x,y)$,必然有$d(x,y)=d(x,root)\oplus d(root,y)$,其中$d(x,y)$表示x到y路径的异或和

接着正解就呼之欲出了:

对于每一个节点$u$,我们均可以计算出其到根节点的异或和,而答案就是$\sum_{i!=j}max\{d(i,root)\oplus d(j,root)\}$

我去这么简单

接下来利用trie树即可完成剩余问题。

什么?没有听说过怎么用trie树求任意两个数的异或最大值,只知道给定一个数求它异或其他数的最大值?(这不就是我吗)

想这么多干啥,trie树一次时间复杂度也就是30左右的大常数,直接把每一个数全部拿来试试不就可以了?

(CaO)

 

 

打代码的时候出现了一点错误调试了很久,以此警示自己:trie树cnt初始值要设为1!!!已经有根节点了!!!!!!!!!

 

代码如下:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int r()
{
    int s=0,k=1;char c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')k=-1;
        c=getchar();
    }
    while(isdigit(c))
    {
        s=s*10+c-'0';
        c=getchar();
    }
    return s*k;
}
int n,head[1000001],cnt;
int s[35];
int ccnt,maxi,tr[10000001][2],f[1000001],tcnt;
struct node
{
    int to,next,dis;
}a[1000001];
void add_edge(int from,int to,int dis)
{
    a[++cnt].to=to;
    a[cnt].dis=dis;
    a[cnt].next=head[from];
    head[from]=cnt;
}
void update(int x)
{
    memset(s,0,sizeof(s));
    ccnt=0;
    while(x)
    {
        if(x&1)s[++ccnt]=1;
        else s[++ccnt]=0;
        x>>=1;    
    }
}
void add(int x)
{
    if(!x)return;
    update(x);
    int now=1;
    for(int i=maxi;i;i--)
    {
        int u=s[i];
        if(!tr[now][u])
        tr[now][u]=++tcnt;
        now=tr[now][u];
    }
}
void dfs(int u,int fa,int now)
{
    f[u]=now;
    maxi=max(maxi,now);
    for(int i=head[u];i;i=a[i].next)
    {
        int v=a[i].to;
        if(v!=fa)dfs(v,u,now^a[i].dis);
    }
}
int sum(int x)
{
    update(x);
    int now=1,mx=0;
    for(int i=maxi;i;i--)
    {
        int u=s[i];
        if(tr[now][u^1])//
        {
            now=tr[now][u^1];
            mx=mx*2+1;
        }
        else 
        {
            now=tr[now][u];
            mx*=2;
        }
    }
    return mx;
}
signed main()
{
    tcnt++;
    n=r();
    int x,y,z;
    for(int i=1;i<n;i++)
    {
        x=r();y=r();z=r();
        add_edge(x,y,z);
        add_edge(y,x,z);
    }
    dfs(1,1,0);
    update(maxi);
    maxi=ccnt;
    int ans=0;
    for(int i=1;i<=n;i++)add(f[i]);
    for(int i=1;i<=n;i++)
    {
    //    cout<<"i:"<<i<<" "<<f[i]<<' '<<sum(f[i])<<endl;
        ans=max(ans,sum(f[i]));
    }
    cout<<ans;
}

 

posted @ 2021-07-12 14:52  lei_yu  阅读(34)  评论(0编辑  收藏  举报