洛谷【P4551】最长异或路径

浅谈\(Trie\)https://www.cnblogs.com/AKMer/p/10444829.html

题目传送门:https://www.luogu.org/problemnew/show/P4551

由于一个数异或自己等于\(0\),所以\(u\)\(v\)的路径边权异或和就是\(u\)\(1\)的路径边权异或和异或上\(v\)\(1\)的路径边权异或和。

所以现在问题变成了给你\(n\)个数,从中选出两个数异或和最大。

按位贪心,每次在\(Trie\)上面找不同的数字异或起来即可。

时间复杂度:\(O(nlogv)\)

空间复杂度:\(O(nlogv)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=1e5+5;

int n,tot,res,dist[maxn];
int now[maxn],pre[maxn<<1],son[maxn<<1],val[maxn<<1];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct Trie {
    int tot;
    int son[maxn*31][2];

    void find(int v) {
        int pos=1,ans=0;
        for(int i=30;~i;i--) {
            int c=v>>i&1;
            if(son[pos][c^1])ans=ans<<1|1,pos=son[pos][c^1];
            else ans=ans<<1,pos=son[pos][c];
        }
        res=max(res,ans);
    }

    void ins(int v) {
        int pos=1;
        for(int i=30;~i;i--) {
            int c=v>>i&1;
            if(son[pos][c])pos=son[pos][c];
            else pos=son[pos][c]=++tot;
        }
    }
}T;

void add(int a,int b,int c) {
    pre[++tot]=now[a];
    now[a]=tot,son[tot]=b,val[tot]=c;
}

void dfs(int fa,int u) {
    for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
        if(v!=fa)dist[v]=dist[u]^val[p],dfs(u,v);
}

int main() {
    n=read(),T.tot=1;
    for(int i=1;i<n;i++) {
        int a=read(),b=read(),c=read();
        add(a,b,c),add(b,a,c);
    }
    dfs(0,1);
    for(int i=1;i<=n;i++) {
        T.find(dist[i]);
        T.ins(dist[i]);
    }
    printf("%d\n",res);
    return 0;
}
posted @ 2019-02-27 19:58  AKMer  阅读(124)  评论(0编辑  收藏  举报