洛谷P4551 最长异或路径【Trie树异或路径】

题目链接:P4551 最长异或路径

题意:n个点的一棵树,两点间的距离是路径上所有边权的异或和;

分析:由树的性质可以想到:dis[u][v]=dis[root][u]^dis[root][v],那么就dfs一棵树出来,更新dis[root][i];

每个点dis的二进制01串建一棵trie,然后从高向低,贪心选取高位异或为1的;

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=5e6+7;
const int mod=1e9+7;
const ll INF=1e18;
int head[maxn],tot=1,dis[maxn],ans;
struct node{int v,w,nxt;} g[maxn];
void add(int u,int v,int w)
{
    g[tot]={v,w,head[u]};
    head[u]=tot++;
}
struct trie //处理异或
{
    int nex[maxn][2],cnt=0;
    void insert(int x) //插入字符串
    {
        int p=0;
        for(int i=30;i>=0;i--)
        {
            int c=((x>>i)&1);
            if(!nex[p][c]) nex[p][c]=++cnt;
            p=nex[p][c];
        }
    }
    int find(int x) //查找字符串
    {    
        int p=0,res=0;
        for(int i=30;i>=0;i--)
        {
            int c=((x>>i)&1);
            if(!nex[p][c^1]) {p=nex[p][c];continue;}
            p=nex[p][c^1];res|=(1<<i);
        }
        ans=max(ans,res);
    }
}Trie;
void dfs(int x,int fa)
{
    Trie.insert(dis[x]);
    Trie.find(dis[x]);//后面的会扫到前面 所以不会漏掉情况
    for(int i=head[x];i;i=g[i].nxt)
    {
        int v=g[i].v,w=g[i].w;
        if(v==fa) continue;
        dis[v]=dis[x]^w;
        dfs(v,x);
    }
}
void rua()
{
    int n;scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
    }
    dfs(1,0);
    printf("%d\n",ans);
}
int main()
{
  rua();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43813163/article/details/105081903