题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大
把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v)
则f(u, v) = f(1, u) ^ f(1, v)
这是显然的
其中f(1, i)是可以再O(n)内处理出来
然后就是在一个数组内,找两个数异或值最大
然后就可以用字典树来搞
每个数变成01串, 然后插入字典树, 第30位在最前,然后29,依次到0位
就建立成了一个深度为31的字典树
对于一个询问,在字典树上找,就是尽量找跟其相反的路径。
比如第30位是0就尽量找最开始是1的路径,实在找不到就只能将这一位妥协,就是一种贪心的思路
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <cmath> #include <algorithm> #include <map> #include <ctime> #define MAXN 212222 #define MAXM 6122222 #define INF 1000000001 using namespace std; int n; int tt, e; struct node { int v, w, next; }edge[MAXN * 2]; int head[MAXN]; struct Trie { int next[2]; void init() { memset(next, 0, sizeof(next)); } }trie[MAXM]; int val[MAXN], vis[MAXN]; void addEdge(int u,int v,int w) { edge[e].v=v;edge[e].next=head[u];edge[e].w=w;head[u]=e++; edge[e].v=u;edge[e].next=head[v];edge[e].w=w;head[v]=e++; } void add(int x) { int u = 0, ind; for(int i = 30; i >= 0; i--) { if(x & (1 << i)) { ind = 1; } else ind = 0; if(!trie[u].next[ind]) { trie[u].next[ind] = ++tt; trie[tt].init(); } u = trie[u].next[ind]; } } int gao(int x) { int u = 0, ind, num = 0; for(int i = 30; i >= 0; i--) { if(x & (1 << i)) ind = 0; else ind = 1; if(trie[u].next[ind]) { num |= (1 << i); u = trie[u].next[ind]; } else u = trie[u].next[!ind]; } return num; } void dfs(int u, int x) { val[u] = x; vis[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; int w = edge[i].w; if(!vis[v]) { dfs(v, x ^ w); } } } int main() { while(scanf("%d", &n) !=EOF) { int u, v, w; for(int i = 0; i <= n; i++) vis[i] = 0; e = 0; memset(head, -1, sizeof(head)); for(int i = 1; i < n; i++) { scanf("%d%d%d", &u, &v, &w); u++; v++; addEdge(u, v, w); } tt = 0; trie[0].init(); dfs(1, 0); int ans = 0; for(int i = 1; i <= n; i++) { ans = max(ans, gao(val[i])); add(val[i]); } printf("%d\n", ans); } return 0; }
时间: 2024-12-14 02:44:31