/*
Trie树,是一种树形结构,是一种哈希树的变种。
应用于统计,排序和保存大量的字符串(但不仅限于字符串,
经常被搜索引擎系统用于文本词频统计。
它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
特点: 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。
https://www.luogu.com.cn/problem/P2580
*/
#include
#include
using namespace std;
const int MAXN = 500001;
int nex[MAXN][26];
int tag[MAXN]; // 该结点结尾的字符串出现次数
int cnt = 0;
void insert(char *s) // 插入字符串
{
int p = 0;
for (int i = 0; s[i]; i++)
{
int c = s[i] - 'a';
if (!nex[p][c]) nex[p][c] = ++cnt; // 如果没有,就添加结点
p = nex[p][c];
}
tag[p] = 1;
}
int find(char *s) // 查找字符串
{
int p = 0;
for (int i = 0; s[i]; i++)
{
int c = s[i] - 'a';
if (!nex[p][c]) break;
p = nex[p][c];
}
return p;
}
int main()
{
int i, n, m, t;
cin >> n;
char name[52] = { '\0' };
for (i = 0; i < n; ++i)
{
cin >> name;
insert(name);
}
cin >> m;
for (i = 0; i < m; ++i)
{
cin >> name;
t = find(name);
if (tag[t] == 0)
cout << "WRONG" << endl;
else if (tag[t] == 1)
{
cout << "OK" << endl;
tag[t] = 2;
}
else
{
cout << "REPEAT" << endl;
}
}
return 0;
}
/*
https://www.luogu.com.cn/problem/P4551
随便指定一个根 root,用T(u, v)表示u 和 v 之间的路径的边权异或和,
那么T(u,v)=T(root, u) ^ T(root,v),因为 LCA 以上的部分异或两次抵消了。
将所有T(root, u)插入到一棵Trie中,就可以求出某个T(root, u)与T(root, v)的最大异或和。
*/
#include
using namespace std;
const int MAXN = 100002;
// 链式前向星存储数
struct node {
int to; // 连接点的编号
int next;// 下一条邻接边的edge下标
int w; // 代表边的权值
} edge[MAXN << 1];
// head[u]: u连接的第一(最后)条边的edge下标
int cnt = 0, head[MAXN] = { 0 };
void add(int u, int v, int w)
{
edge[++cnt].next = head[u]; // 采用头插法
head[u] = cnt;
edge[cnt].to = v;
edge[cnt].w = w;
}
// dis[i]: i节点到根节点的边权异或和
int dis[MAXN] = { 0 };
void dfs(int u, int fa)
{
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (v == fa)
continue;
dis[v] = dis[u] ^ edge[i].w;
dfs(v, u);
}
}
int index = 0;
// 权值为int, int占4个字节,即32位, 按dis[i]二进制数建trie,由二进制的高位到低位依次插入
int nxt[MAXN << 5][2];
void insert(int x)
{
int u = 0, c = 0;
// 从高位到低位截取边权异或和
for (int i = 31; i >=0; --i)
{
c = ((x >> i) & 1);
if (!nxt[u][c])
nxt[u][c] = ++index;
u = nxt[u][c];
}
}
/*
贪心选择:为了求最大的异或值,从高位到低位扫描二进制x, 每次向与当前位数值不同的节点走,
如果能这么走,res的这一位为1;如果不这么走,res的这一位为0。
最后走到叶节点时,此时的res就是某个dis[x]与dis[y]异或得到的最大值
*/
int get(int x)
{
int res = 0, u = 0, c = 0;
// 从高位到低位截取边权异或和
for (int i = 31; i >=0; --i)
{
c = ((x >> i) & 1);
if (nxt[u][c^1]) // 如果能向和当前位不同的子树走,就向那边走
{
u = nxt[u][c^1];
res |= (1 << i);
}
else
u = nxt[u][c];
}
return res;
}
int main()
{
int i, n, u, v, w;
cin >> n;
for (i = 1; i < n; ++i)
{
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
dfs(1, 0);
for (i = 1; i <= n; ++i)
insert(dis[i]);
int sum = 0;
for (i = 1; i <= n; ++i)
sum = max(sum, get(dis[i]));
cout << sum << endl;
return 0;
}