题意:一棵 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; }
时间: 2024-11-25 11:25:21