树上异或和最大
http://poj.org/problem?id=3764
题意:求上任意两点的边权异或最大值。
解法:dfs遍历树的同时将异或值加入01字典树中,同时查询最大异或值。
这样为什么就能保证你所求的结果对应的路径是连续的呢?考虑三种情况:
1.深搜的两条路径一个包含在另一个中,这样一异或,公共的部分的值变成 0 了,剩下的部分是连续的。
2.深搜的两条路径部分重叠,同理,异或后公共的部分变成 0 了,由于是对边权的异或,剩下的部分仍然连续。
3.深搜的两条路径不重叠,但是两条路径肯定有公共的点——根节点,也是连续的。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 1000000007 #define PI acos(-1) using namespace std; typedef unsigned long long ll ; const int N = 100009; int tree[N*32][2] , vis[N*32] , tol; int head[N] , cnt; int v[N]; int ans ; struct node{ int to , next , w ; }a[N*2]; void add(int u , int v , int w) { a[cnt].to = v ; a[cnt].next = head[u]; a[cnt].w = w ; head[u] = cnt++; } void insert(int x) { int u = 0 ; for(int i = 31 ; i >= 0 ; i--) { int p = (x >> i) & 1; if(!tree[u][p]) tree[u][p] = ++tol; u = tree[u][p]; } vis[u] = x ; } int research(int x) { int u = 0 ; for(int i = 31 ; i >= 0 ; i--) { int p = (x >> i) & 1 ; if(tree[u][p^1]) u = tree[u][p^1]; else u = tree[u][p]; } return vis[u] ^ x ; } void dfs(int u , int val) { v[u] = 1 ; insert(val); for(int i = head[u] ; i != -1 ; i = a[i].next) { int vv = a[i].to ; if(v[vv]) continue ; ans = max(ans , research(val ^ a[i].w)); dfs(vv, val^a[i].w); } } void init() { memset(vis , 0 , sizeof(vis)); memset(tree , 0 , sizeof(tree)); memset(v , 0 , sizeof(v)); memset(head , -1 , sizeof(head)); cnt = 0 ; tol = 0 ; ans = 0 ; } int main() { int n ; while(~scanf("%d" , &n)) { init(); for(int i = 0 ; i < n - 1 ; i++) { int u , v , w ; scanf("%d%d%d" , &u , &v , &w); add(u , v , w); add(v , u , w); } dfs(0 , 0); cout << ans << endl ; } return 0; }