题意:一棵 n 个结点的树,树边有权值w(0 <= w < 2^31),求最两结点间的最大异或。
题目链接:http://poj.org/problem?id=3764
——>>取0为根,预处理出所有结点到根的异或xOr[i]。那么结点 a 与结点 b 之间的路径异或就是xOr[a] ^ xOr[b]。。
权值 w 最多31位,于是,将每个xOr的二进制表示从高位到低位插入到 01 Trie中(0为0,非0为1)。。
查询时从高位开始贪心。。
很好的题目,第一次不在字母上使用Trie。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::max;
const int MAXN = 100000 + 10;
const int MAX_NODE = 3000000 + 10;
const int MAX_X = 2;
const int MAX_BIT = 30;
struct EDGE
{
int to;
int w;
int nxt;
} edge[MAXN << 1];
int n;
int hed[MAXN], ecnt;
int xOr[MAXN];
int ch[MAX_NODE][MAX_X], sz;
void Init()
{
ecnt = 0;
memset(hed, -1, sizeof(hed));
xOr[0] = 0;
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void AddEdge(int u, int v, int w)
{
edge[ecnt].to = v;
edge[ecnt].w = w;
edge[ecnt].nxt = hed[u];
hed[u] = ecnt++;
}
void Read()
{
int u, v, w;
for (int i = 0; i < n - 1; ++i)
{
scanf("%d%d%d", &u, &v, &w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
}
void Dfs(int u, int fa)
{
for (int e = hed[u]; e != -1; e = edge[e].nxt)
{
int v = edge[e].to;
if (v != fa)
{
xOr[v] = xOr[u] ^ edge[e].w;
Dfs(v, u);
}
}
}
void Insert(int x)
{
int u = 0;
for (int i = MAX_BIT; i >= 0; --i)
{
int cur = ((1 << i) & x) > 0 ? 1 : 0;
if (!ch[u][cur])
{
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][cur] = sz++;
}
u = ch[u][cur];
}
}
void Insert()
{
for (int i = 0; i < n; ++i)
{
Insert(xOr[i]);
}
}
int Query(int x)
{
int ret = 0, u = 0;
for (int i = MAX_BIT; i >= 0; --i)
{
int cur = ((1 << i) & x) > 0 ? 1 : 0;
if (ch[u][!cur])
{
ret |= (1 << i);
u = ch[u][!cur];
}
else
{
u = ch[u][cur];
}
}
return ret;
}
void Query()
{
int ret = 0;
for (int i = 0; i < n; ++i)
{
ret = max(ret, Query(xOr[i]));
}
printf("%d\n", ret);
}
int main()
{
while (scanf("%d", &n) == 1)
{
Init();
Read();
Dfs(0, -1);
Insert();
Query();
}
return 0;
}