poj3764 经典题 trie树+邻接表dfs

题意:有一个n个节点的树,每条边都有一个权值,一条路径的权值等于指此条路径上所有边权值的异或值。问此棵树权值最大的路径的权值是多少;

解法:先算出每个点到0节点的路径的权值,(dfs一遍即可,由于n最大是5个0,所以要邻接表建图进行dfs)。以后每两个节点之间的路径权值就等于分别与0节点之间权值的异或值(用到一个公式:a^b=(a^c)^(b^c)).所以以后两两比较即可,但是n^2肯定不行,这时就可以用到trie树了。将每个节点的ans[i] (i节点与0节点之间的路径权值) 插入trie树,然后再将每个ans[i]访问并返回最大值,访问时贪心往从高位向低位遍历,每位尽量向反方向走(能保证异或值的最大化)。每次的返回值松弛答案,注意每个ans[i]也要将答案松弛一番,因为答案也有可能是i节点与0节点之间的路径。
代码:

/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>

using namespace std;

#define eps 1e-8
typedef long long LL;
struct edge
{
    int v;
    int next;
    int num;
} edges[200100];
int n;
int ans[100100];
int count1=0;
int head[100100];
bool rem[100100];
void addedge(int u,int v,int num)
{
    edges[count1].v=v;
    edges[count1].num=num;
    edges[count1].next=head[u];
    head[u]=count1++;
}
int count2=1;
struct point
{
    int num[2];
} points[3000100];
int getans(int k,int p)
{
    int ans=0;
    for(int i=30;i>=0;i--)
    {
        if((1<<i)&k)
        {
         if(points[p].num[0])
            ans+=1<<i,p=points[p].num[0];
         else
            p=points[p].num[1];
        }
        else
        {
            if(points[p].num[1])
            ans+=1<<i,p=points[p].num[1];
            else
            p=points[p].num[0];
        }
    }
    return ans;
}
void insert(int k,int p)
{
    for(int i=30;i>=0;i--)
    {
        if(k&(1<<i))
        {
           if(points[p].num[1])
            p=points[p].num[1];
          else
            points[p].num[1]=count2++,p=count2-1;
        }
        else
        {
             if(points[p].num[0])
             p=points[p].num[0];
          else
            points[p].num[0]=count2++,p=count2-1;
        }
    }
}
void dfs(int k)
{
    if(rem[k]) return ;
     rem[k]=1;
    for(int i=head[k];i!=-1;i=edges[i].next)
    {
        int t=edges[i].v;
        ans[t]=ans[k]^edges[i].num;
        dfs(t);
    }
}


void inite()
{
    memset(head,-1,sizeof head);
    memset(rem,0,sizeof rem);
    memset(edges,0,sizeof edges);
    memset(points,0,sizeof points);
    memset(ans,0,sizeof ans);
    count1=0;
    count2=1;
}
int main()
{
  while(scanf("%d",&n)!=EOF)
  {
  inite();
  for(int i=1;i<n;i++){
      int a,b,c;
      scanf("%d%d%d",&a,&b,&c);
      addedge(a,b,c);
      addedge(b,a,c);
  }
  dfs(0);
  for(int i=1;i<n;i++)
      insert(ans[i],0);
  int ans1=0;
  for(int i=1;i<n;i++)
    ans1=max(ans1,getans(ans[i],0)),ans1=max(ans1,ans[i]);
  cout<<ans1<<'\n';
  }
   return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值