给定一个树,树上的边都具有权值。

树中一条路径的异或长度被定义为路径上所有边的权值的异或和:

formula.png

⊕ 为异或符号。

给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?

输入格式
第一行包含整数n,表示树的节点数目。

接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。

输出格式
输出一个整数,表示异或长度最大的路径的最大异或和。

数据范围
1≤n≤100000,
0≤u,v<n,
0≤w<231
输入样例:
4
0 1 3
1 2 4
1 3 6
输出样例:
7
样例解释
样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)

我们不妨设置一个数组D[x]表示根节点到x的路径上所有的边权的xor值,那么很显然,D[x]=D[father(x)] xor weight(x,father(x)) 也就是D[x节点的父亲]异或上x节点到他父亲的路径.既然如此的话,我们明显发现这道题目D数组是可以通过深度优先搜索求出.
求出所有的D数组,那么x节点到y节点上所有的异或权值就是D[x] xor D[y],换句话来说就是,从根节点到x节点的xor值,和根节点到y节点的xor值,这两条路径重叠了,然后这两条路径就抵消了,因为a xor a=0.本身和本身xor值是0的.

因此我们原问题就转换成为D[1]~D[n]中选择任意两个数,xor的结果值就会变成最大.也就是上一道题目.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=100000*2+100;
int f[N],n;
bool used[N];
//vector pair 存图
vector<pair<int,int> > g[N];

void dfs(int u){
    if(!used[u]){
        used[u]=true;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i].first;
            int w=g[u][i].second;
            if(!used[v]){
                f[v]=f[u]^w;
                dfs(v);
            }
        }
    }
}

//建立字典树
int son[N*32][2],idx;//注意内存
void insert(int x){
    int p=0;
    for(int i=30;i>=0;i--){
        int s=x>>i&1;
        if(!son[p][s]) son[p][s]=++idx;
        p=son[p][s];
    }
}

int search(int x){
    int p=0,res=0;
    for(int i=30;i>=0;i--){
        int s=x>>i&1;
        if(son[p][!s]) {
            res+=1<<i;
            p=son[p][!s];
        }
        else p= son[p][s];
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v,w;
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
       }
    dfs(0);

    int ans=0;
    for(int i=0;i<n;i++) insert(f[i]);
    for(int i=0;i<n;i++) ans=max(ans,search(f[i]));
    cout<<ans<<endl;
    return 0;
}

 posted on 2019-08-06 16:12  谁是凶手1703  阅读(73)  评论(0)    收藏  举报