POJ 3764 The xor-longest Path Trie

The xor-longest Path
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 6954 Accepted: 1481
Description

In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p:

⊕ is the xor operator.

We say a path the xor-longest path if it has the largest xor-length. Given an edge-weighted tree with n nodes, can you find the xor-longest path?  

Input

The input contains several test cases. The first line of each test case contains an integer n(1<=n<=100000), The following n-1 lines each contains three integers u(0 <= u < n),v(0 <= v < n),w(0 <= w < 2^31), which means there is an edge between node u and v of length w.

Output

For each test case output the xor-length of the xor-longest path.
Sample Input

4
0 1 3
1 2 4
1 3 6
Sample Output

7
Hint

The xor-longest path is 0->1->2, which has length 7 (=3 ⊕ 4)

题意:
给一棵树,每条路上有边权,求两点之间异或和最大是多少。

分析:
求两点之间的异或和显然不好求。但对每个节点,求它到根节点的异或和dis[i]显然是没问题的。
而两点之间的异或和就可以用dis[u]|dis[v];
接下来就是Trie树的部分了。
求异或和最大显然是Trie树的典型应用。对每个数查询的时候,从高位到低位,如果它的这一位是1的话,我们就贪心地选择0的那一条路,如果没有的为0的那边,才走为1的那条路。反之。然后将这个数插入Trie树中。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;

const int N = 400010;

int n;
int num=0,head[N];

inline int Max(int a,int b){
    return a>b?a:b;
}

struct node{
    int pre,u,v,w;
}edge[N*4];

void addedge(int from,int to,int w){
    num++;
    edge[num].pre=head[from];
    edge[num].u=from;
    edge[num].v=to;
    edge[num].w=w;
    head[from]=num;
}

int tt=0;
struct Trie{
    int nxt[2];
    int num[2];

    void newnode(){
        ms(num,0);}
}t[N*4];

void add(int x){
    int root=0,cnt;
    for(int i=30;i>=0;i--){
        if(x&(1<<i)) cnt=1;
        else cnt=0;
        if(!t[root].nxt[cnt]){
            t[root].nxt[cnt]=++tt;
            t[tt].newnode();
        }
        root=t[root].nxt[cnt];
    }
}

int Getresult(int x){
    int ans=0,cnt,root=0;
    for(int i=30;i>=0;i--){
        if(x&(1<<i)) cnt=0;
        else cnt=1;
        if(t[root].nxt[cnt]){
           ans|=(1<<i);
           root=t[root].nxt[cnt];
        }
        else root=t[root].nxt[!cnt];
    }
    return ans;
}

bool vis[N];
int dis[N];
void dfs(int u,int w){
    vis[u]=true;dis[u]=w;
    for(int i=head[u];i;i=edge[i].pre){
        int v=edge[i].v;
        if(vis[v]) continue;
        dfs(v,w^edge[i].w);
    }
}

int ans;
void update(){
    ms(dis,0);ms(vis,0);ms(head,0);ms(t,0);
    t[0].newnode();tt=0,ans=-1;
}

int main(){
    while(scanf("%d",&n)!=EOF){
      update();
      for(register int i=1;i<n;i++){
         int u,v,w;
         scanf("%d%d%d",&u,&v,&w);
         addedge(u,v,w);
         addedge(v,u,w);
      }
      dfs(0,0);
      for(register int i=0;i<n;i++){
         ans=Max(ans,Getresult(dis[i]));
         add(dis[i]);
      }
      printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值