【Coel.学习笔记】【一个阶段的结束】01-Trie树(01字典树)求异或路径
作者:互联网
题前闲语
是的,变成闲语了(别问我为什么要改)
今天考完了月考,虽然发挥得不是很好但终归是结束了,休息一下~
刚好深进也到货了,开始新一轮学习吧!
题目简介
题目描述
给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
输入输出格式
输入格式
第一行一个整数 \(n\),表示点数。
接下来 \(n-1\) 行,给出 \(u,v,w\) ,分别表示树上的 \(u\) 点和 \(v\) 点有连边,边的权值是 \(w\)。
输出格式
一行,一个整数表示答案。
解题思路
考虑用链式前向星存图,求出每个节点到根节点(自行定义根节点为\(1\))的异或路径,那么两个节点的异或路径就是它们与根节点路径的异或值。
先用\(dfs\)初始化每个节点的异或值:
struct edge {
int next, to, w;
} edge[maxn];
int p[maxn], cnt;
void add_edge(int u, int v, int w) {
edge[++cnt].next = p[u];
edge[cnt].to = v;
edge[cnt].w = w;
p[u] = cnt;
}
void init(int x, int f) {//dfs
for (int i = p[x]; i != 0; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if (v != f) {
s[v] = s[x] ^ w;
init(v, x);
}
}
}
然后暴力枚举。当然直接暴力枚举的话复杂度是\(O(n^2)\),没法通过\(n=10^5\),所以需要用\(01-Trie\)优化。
(此处待补充)
代码如下:
#include <cctype>
#include <cstdio>
#include <iostream>
#include <vector>
namespace FastIO {
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
static int buf[35];
int top = 0;
do {
buf[top++] = x % 10;
x /= 10;
} while (x);
while (top)
putchar(buf[--top] + '0');
puts("");
}
} // namespace FastIO
using namespace std;
using namespace FastIO;
const int maxn = 1e5 + 10;
struct edge {
int next, to, w;
} edge[maxn];
int p[maxn];
int n, cnt, tot, ans;
int s[maxn], ch[maxn * 32][2];
void add_edge(int u, int v, int w) {
edge[++cnt].next = p[u];
edge[cnt].to = v;
edge[cnt].w = w;
p[u] = cnt;
}
void init(int x, int f) {
for (int i = p[x]; i != 0; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if (v != f) {
s[v] = s[x] ^ w;
init(v, x);
}
}
}
void insert(int v) {
int u = 0;
for (int i = (1 << 30); i; i >>= 1) {
bool c = v & i;
if (!ch[u][c])
ch[u][c] = ++tot;
u = ch[u][c];
}
}
int find(int v) {
int ans = 0, u = 0;
for (int i = (1 << 30); i; i >>= 1) {
bool c = v & i;
if (ch[u][!c]) {
ans += i;
u = ch[u][!c];
} else
u = ch[u][c];
}
return ans;
}
int main() {
n = read();
for (int i = 1; i <= n - 1; i++) {
int u = read(), v = read(), w = read();
add_edge(u, v, w);
add_edge(v, u, w);
}
init(1, -1);
for (int i = 1; i <= n; i++)
insert(s[i]);
for (int i = 1; i <= n; i++)
ans = max(ans, find(s[i]));
write(ans);
return 0;
}
标签:cnt,ch,求异,int,Coel,edge,异或,01,maxn 来源: https://www.cnblogs.com/Coel-Flannette/p/16083857.html