【Trie树】POJ 3764 最大连续异或和
题意
已知:给出n个结点的树,定义两结点间的权值为两点之间所有边相异或的值。
求:树中的某两点间的最大权值。
解法
是道好题,在做HDU5845,发现Trie树解决连续异或和问题是很有趣的套路,遂找到这题学习。
//TODO
代码
POJ 数据范围有坑,TLE半天,点开Discuss发现数据范围可能是200000。
//Trie树求最大/最小连续异或和
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 2e5 + 6;
const int MAXBIT = 30;
struct edge
{
int nx, v, w;
}e[MAXN << 1];
int last[MAXN];
int etot;
int n;
struct Trie
{
int child[2];
void init()
{
child[1] = child[0] = -1;
}
}tr[MAXN << 5];
int cnt;
bool vis[MAXN];
int XOR[MAXN];
void add_edge(int u, int v, int w)
{
e[etot].nx = last[u];
e[etot].v = v;
e[etot].w = w;
last[u] = etot++;
e[etot].nx = last[v];
e[etot].v = u;
e[etot].w = w;
last[v] = etot++;
}
void Insert(int x)
{
int cur = 0;
for (int i = MAXBIT; i >= 0; --i)
{
int k = (x >> i) & 1;
if (tr[cur].child[k] == -1)
{
tr[cur].child[k] = ++cnt;
tr[cnt].init();
}
cur = tr[cur].child[k];
}
}
int Find(int x)
{
int cur = 0;
int ans = 0;
for (int i = MAXBIT; i >= 0; --i)
{
int k = ((x >> i) & 1)? 0 : 1;
if (tr[cur].child[k] != -1)
{
ans |= (1 << i);
cur = tr[cur].child[k];
}
else
cur = tr[cur].child[1 - k];
}
return ans;
}
void dfs(int u)
{
//Insert(XOR[u]);
vis[u] = 1;
for(int k = last[u]; k != -1; k = e[k].nx)
{
if (vis[e[k].v]) continue;
else XOR[e[k].v] = XOR[u] ^ e[k].w;
dfs(e[k].v);
}
}
void init()
{
etot = 0;
//memset(last, 0xFF, sizeof(last));
cnt = 0;
tr[0].init();
for(int i = 0; i < n; ++i)
{
last[i] = -1;
vis[i] = XOR[i] = 0;
}
//memset(vis, 0, sizeof(vis));
//memset(XOR, 0, sizeof(XOR));
}
int main()
{
int ans, u, v, w;
//while(cin>>n)
while(scanf("%d", &n) == 1)
{
init();
for (int i = 1; i < n; ++i)
{
scanf("%d%d%d", &u, &v, &w);
//cin>>u>>v>>w;
add_edge(u,v,w);
}
dfs(0);
ans = -1;
for (int i = 0; i < n; ++i)
{
Insert(XOR[i]);
int t = Find(XOR[i]);
ans = max(ans, t);
}
printf("%d\n", ans);
//cout<<ans<<endl;
}
return 0;
}
参考
http://codecloud.net/86072.html
https://problemsolvingnotes.wordpress.com/2012/02/22/poj-3764-the-xor-longest-path/