The XOR-longest Path(Bzoj1954)

试题描述
给定一棵 n 个点的带权树,求树上最长的异或和路径。
输入
多组数据。
每组数据第一行一个整数 n(1≤n≤10^5),接下来 n−1 行每行三个整数 u,v,w,表示 u,v 之间有一条长度为 w 的边。(0≤u,v<n,0≤w<2^31)
输出
对于每组数据输出答案。
输入示例
4
1 2 3
2 3 4
2 4 6
输出示例
7

论一个人能sb到什么程度

写了半天发现多写了一个取反QAQ

日常被卡,这题的数据范围好像给错了

然后既然是关于异或的,我们肯定要想到Trie,将每条路径的异或和求出(首位补零)

然后在Trie树上跑一遍,尽量选择与它的当前为不同的

相加就可以了

下面给出代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int n;
int trie[1000006][2];
int tot=1;
int head[1000006];
int nxt[1000006];
int to[1000006];
int total=0;
int v[1000006];
void add(int x,int y,int z){//邻接表连边 
    total++;
    to[total]=y;
    v[total]=z;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int a[1000006];
void pre(int x){
    int c=1;
    for(int i=0;i<=30;i++){
        a[i]=x&1;
        x>>=1;
    }
    reverse(a,a+31);//正序建树  补零 
    for(int i=0;i<=30;i++){
        int s=a[i];
        if(!trie[c][s]) trie[c][s]=++tot;
        c=trie[c][s];
    }
    return ;
}
int num[1000006];
void dfs(int x,int fa){//计算每一条路径的异或和 
    for(int e=head[x];e;e=nxt[e]){
        if(to[e]==fa) continue;
        num[to[e]]=num[x]^v[e];
        dfs(to[e],x);
    }
    return ;
}
int check(int x){
    int c=1;
    int sum=0;
    for(int i=0;i<=30;i++){
        a[i]=x&1;
        x>>=1;
    }
    reverse(a,a+31);
    for(int i=0;i<=30;i++){
        int s=a[i];
        if(trie[c][!s]){//尽量选择不同的 让异或和最大 
            c=trie[c][!s];
            sum+=(1<<30-i);
        }
        else c=trie[c][s];
    }
    return sum;
}
int main(){
    while(cin>>n){
        memset(trie,0,sizeof(trie));
        memset(num,0,sizeof(num));
        memset(head,0,sizeof(head));//赋初值 
        total=0;
        tot=1;
        for(int i=1;i<n;i++){
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);
            add(y,x,z);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++) pre(num[i]);
        int ans=0;
        for(int i=1;i<=n;i++) ans=max(ans,check(num[i]));//取最大值 
        printf("%d",ans);
    }
    return 0;
}

 

posted @ 2018-09-28 20:06  Bruce--Wang  阅读(214)  评论(0编辑  收藏  举报