Description

给定 \(n\) 个点的带边权树,求一条异或和最大的简单路径

Input

第一行是点数 \(n\)

下面 \(n - 1\) 行每行三个整数描述这棵树

Output

输出一个数代表答案

Hint

\(1~\leq~n~\leq~10^5~,~1~\leq~w~<~2^{31}\),其中 \(w\) 是最大边权

Solution

考虑由于自身异或自身对答案无贡献,对于两个点 \(u,v\),他们简单路径上的异或和即为他们分别向根节点求异或和的两个值的疑惑值。

然后考虑枚举每个点,设它向根求异或和的值为 \(c\),寻找另一个能够最大化异或值的点。显然要从高到低考虑。高位不够优秀的可以直接扔掉,我们考虑到底 \(i\) 位时,所有没有被扔掉的点中,如果 \(c\) 的第 \(i\) 位为 \(1\),则为了让答案更大,我们尽可能的选择第 \(i\) 位为 \(0\) 的点,反过来同理。

于是问题变成了动态判断是否存在符合要求的异或和。我们建立一棵 \(01\) trie来维护所有的异或和,然后在树上反着走即可。

时空复杂度 \(O(n~\log w)\)。不过略微有点小卡空间

Code

#include <cstdio>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define ci const int
#define cl const long long typedef long long int ll; namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
} template <typename T>
inline void qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
} template <typename T>
inline void ReadDb(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
} namespace OPT {
char buf[120];
} template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = char(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
} const int maxn = 100010;
const int maxm = 200010;
const int maxt = 6200010; struct Edge {
Edge *nxt;
int to, v;
};
Edge eg[maxm], *hd[maxn]; int ecnt;
inline void cont(ci from, ci to, ci v) {
Edge &e = eg[++ecnt];
e.to = to; e.nxt = hd[from]; e.v = v; hd[from] = &e;
} struct Tree {
Tree *son[2];
};
Tree qwq[maxt], *rot;
int top; int n, ans;
int dist[maxn]; void reading();
void dfs(ci, ci);
void buildroot();
void build(Tree*, ci, ci);
int check(Tree*, ci, ci); int main() {
freopen("1.in", "r", stdin);
qr(n);
reading();
dfs(1, 0);
buildroot();
for (int i = 1; i <= n; ++i) build(rot, dist[i], 31);
for (int i = 1; i <= n; ++i) ans = std::max(ans, check(rot, dist[i], 31) ^ dist[i]);
qw(ans, '\n', true);
return 0;
} void reading() {
int a, b, c;
for (int i = 1; i < n; ++i) {
a = b = c = 0; qr(a); qr(b); qr(c);
cont(a, b, c); cont(b, a, c);
}
} void dfs(ci u, ci fa) {
for (Edge *e = hd[u]; e; e = e->nxt) {
int &to = e->to;
if (to == fa) continue;
dist[to] = dist[u] ^ e->v; dfs(to, u);
}
} void buildroot() {
rot = qwq; top = 1;
} void build(Tree *u, ci v, ci cur) {
if (cur < 0) return;
int k = static_cast<bool>((1 << cur) & v);
build(u->son[k] ? u->son[k] : u->son[k] = qwq + (top++), v, cur - 1);
} int check(Tree *u, ci v, ci cur) {
if (cur < 0) return 0;
int k = (static_cast<bool>((1 << cur) & v)) ^ 1;
return u->son[k] ? (check(u->son[k], v, cur - 1) | (k << cur)) : check(u->son[k ^ 1], v, cur - 1) | ((k ^ 1) << cur);
}

Summary

对于异或和一类的题目,考虑自身异或两遍对答案无贡献的情况。

动态判断一个串是否存在可以使用踹树来维护。

【trie树】【P4551】 最长异或路径的更多相关文章

  1. [luogu] P4551 最长异或路径(贪心)

    P4551 最长异或路径 题目描述 给定一棵\(n\)个点的带权树,结点下标从\(1\)开始到\(N\).寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或 ...

  2. P4551 最长异或路径 (01字典树,异或前缀和)

    题目描述 给定一棵 n 个点的带权树,结点下标从 1 开始到 N .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式: 第一行一 ...

  3. P4551 最长异或路径

    题目描述 给定一棵 nnn 个点的带权树,结点下标从 111 开始到 NNN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式 ...

  4. 洛谷 P4551 最长异或路径

    题目描述 给定一棵 nn 个点的带权树,结点下标从 11 开始到 NN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有节点权值的异或. 输入输出格式 输入格式: ...

  5. 洛谷P4551 最长异或路径

    传送门:https://www.luogu.org/problem/show?pid=4551 在看这道题之前,我们应懂这道题怎么做:给定n个数和一个数m,求m和哪一个数的异或值最大. 一种很不错的做 ...

  6. Luogu P4551 最长异或路径

    题目链接 \(Click\) \(Here\) \(01Trie\)好题裸题. 取节点\(1\)为根节点,向下扫每一个点从根节点到它路径上的异或和,我们可以得到一个\(sumx[u]\). 现在路径异 ...

  7. 2018.10.26 洛谷P4551 最长异或路径(01trie)

    传送门 直接把每个点到根节点的异或距离插入01trie. 然后枚举每个点在01trie上匹配来更新答案就行了. 代码: #include<iostream> #include<cst ...

  8. Luogu P4551 最长异或路径 01trie

    做一个树上前缀异或和,然后把前缀和插到$01trie$里,然后再对每一个前缀异或和整个查一遍,在树上从高位向低位贪心,按位优先选择不同的,就能贪出最大的答案. #include<cstdio&g ...

  9. luoguP4551最长异或路径

    P4551最长异或路径 链接 luogu 思路 从\(1\)开始\(dfs\)求出\(xor\)路径.然后根据性质\(x\)到\(y\)的\(xor\)路径就是\(xo[x]^xo[y]\) 代码 # ...

  10. 【ybt高效进阶2-4-3】【luogu P4551】最长异或路径

    最长异或路径 题目链接:ybt高效进阶2-4-3 / luogu P4551 题目大意 给定一棵 n 个点的带权树,结点下标从 1 开始到 N.寻找树中找两个结点,求最长的异或路径. 异或路径指的是指 ...

随机推荐

  1. python - 定时清理ES 索引

    只保留三天 #!/usr/bin/env python3 # -*- coding:utf-8 -*- import os import datetime # 时间转化为字符串 now_time = ...

  2. 离线人脸识别 ArcFaceSharp -- ArcFace 2.0 SDK C#封装库分享

    ArcFaceSharp ArcFaceSharp 是ArcSoft 虹软 ArcFace 2.0 SDK 的一个 C# 封装库,为方便进行 C# 开发而封装.欢迎 Start & Fork. ...

  3. Linux命令之mount挂载

    挂载概念 Linux中的根目录以外的文件要想被访问,需要将其“关联”到根目录下的某个目录来实现,这种关联操作就是“挂载”,这个目录就是“挂载点”,解除次关联关系的过程称之为“卸载”. 注意:“挂载点” ...

  4. linux磁盘扩容日志

    //针对ext4文件格式的操作系统(如CentOS6):// umount /dev/vdb e2fsck -f /dev/vdb resize2fs /dev/vdb mount /dev/vdb ...

  5. DebuggerVisualizer时,序列化引出的问题。

    实现如下功能:http://www.cnblogs.com/devil0153/archive/2010/09/01/Visual-Studio-Custom-Debugger.html#288924 ...

  6. python中数据分析常用函数整理

    一. apply函数 作用:对 DataFrame 的某行/列应用函数之后,Apply 返回一些值.函数既可以使用默认的,也可以自定义.注意:在第二个输出中应用 head() 函数,因为它包含了很多行 ...

  7. Daily Scrumming 2015.10.22(Day 3)

    今明两天任务表 Member Today’s Task Tomorrow’s Task 江昊 学习rails ActiveRecord 购买.注册域名 继续学习rails ActiveRecord 数 ...

  8. Linux 基础入门第一次实验笔记

    第一节.实验介绍 本节主要介绍 Linux 的历史,Linux 与 Windows 的区别等入门知识.如果你已经有过充分的了解,可以跳过本节,直接进入下一个实验. 一.Linux 为何物 Linux ...

  9. 实验1 熟悉Linux开发环境 实验报告

    参见http://www.cnblogs.com/lhc-java/p/4970269.html

  10. 第二阶段Sprint3

    昨天:查看资料,开始视频录制部分的代码实现 今天:事实现保存到指定路径,并能够选择播放 遇到的问题:自动生成文件名,是否需要自己命名?怎么实现?