ACwing 144. 最长异或值路径 字典树
给定一个树,树上的边都具有权值。
树中一条路径的异或长度被定义为路径上所有边的权值的异或和:
formula.png
⊕ 为异或符号。
给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?
输入格式
第一行包含整数n,表示树的节点数目。
接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。
输出格式
输出一个整数,表示异或长度最大的路径的最大异或和。
数据范围
1≤n≤100000
,
0≤u,v<n,
0≤w<231
输入样例:
4
0 1 3
1 2 4
1 3 6
输出样例:
7
样例解释
样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)
题意: 一棵树,有边权,求任意两点 U,V的路径上的亦或和最大
先推荐Y总的视频题解: https://www.acwing.com/video/81/
首先,假如选定一个根节点(例如0节点),
设根节点大到 U节点的异或和为 sumu
如下图, 5和 9的路径异或和应该为 sum5 xor sum9
因为 sum2会被 xor两次而消掉
dfs求出到每个点的路径异或和 sumu后,就变成了:
从 n个 sumu里挑出 A和 B,使得 A xor B最大,
也就是AcWing 143. 最大异或对那题的题意
#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>
#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)
using namespace std;
#define show(x...) \ do { \ cout << "\033[31;1m " << #x << " -> "; \ err(x); \ } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
namespace FastIO{
char print_f[105];
void read() {}
void print() { putchar('\n'); }
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
x = 0;
char ch = getchar();
ll f = 1;
while (!isdigit(ch)) {
if (ch == '-') f *= -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
ll p3=-1;
if(x<0) putchar('-'), x=-x;
do{
print_f[++p3] = x%10 + 48;
} while(x/=10);
while(p3>=0) putchar(print_f[p3--]);
putchar(' ');
print(oth...);
}
} // namespace FastIO
using FastIO::print;
using FastIO::read;
int n, m, Q, K;
/** struct Node { Node* next[2]; Node() { memset(next, false, sizeof(next)); } } *root = new Node(); */
#define ch ( x >> i & 1 )
#define N 31
#if 0
void insert(int x) {
Node* now = root;
for(int i=N; i>=0; i--) {
if(!now->next[ch]) now->next[ch] = new Node();
now = now->next[ch];
}
}
int search(int x) {
Node* now = root;
int ans = 0;
for(int i=N; i>=0; i--) {
if(now->next[!ch]) {
ans += 1 << i;
now = now->next[!ch];
} else {
now = now->next[ch];
}
}
return ans;
}
#endif
struct Node {
int v, w;
} ;
vector<Node> G[MAXN];
int a[MAXN], tot;
int tree[MAXN*32][2];
void insert(int x) {
int now = 0;
for(int i=N; i>=0; i--) {
if(!tree[now][ch]) tree[now][ch] = ++tot;
now = tree[now][ch];
}
}
int search(int x) { //找打一个数,尽量使得二进制位前面的1最多
int now = 0, ans = 0;
for(int i=N; i>=0; i--) {
if(tree[now][!ch]) { //因为不同才为1,所以每一步尽量走相反的位
ans += 1 << i;
now = tree[now][!ch];
} else {
now = tree[now][ch];
}
}
return ans;
}
bool vis[MAXN];
void dfs(int u, int sum) {
vis[u] = true;
a[u] = sum;
for(auto ed : G[u]) {
int v = ed.v;
if(vis[v]) continue ;
dfs(v, sum^ed.w);
}
}
int main() {
#ifdef debug
freopen("test", "r", stdin);
clock_t stime = clock();
#endif
read(n);
int u, v, w;
for(int i=1; i<n; i++) {
read(u, v, w);
G[u].push_back({v, w}), G[v].push_back({u, w});
}
dfs(0, 0);
for(int i=0; i<n; i++)
insert(a[i]);
int ans = 0;
for(int i=0; i<n; i++)
ans = max(ans, search(a[i]));
printf("%d\n", ans);
#ifdef debug
clock_t etime = clock();
printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif
return 0;
}