BZOJ 1954 (POJ 3764) Trie的经典应用 求树上最大异或值

来源:互联网 发布:怎么开企业淘宝店铺 编辑:程序博客网 时间:2024/06/05 20:34

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1954 (然而这是权限题…… 所以还是看POJ 3764吧)

感谢黄学长。。涨姿势了。。

树上路径问题,xor运算满足分配率交换律,先求出每个节点到根节点的路径权值,这样就转化为从一堆值中选出两个xor起来最大的。

于是把这一堆值(不足30位的补到30位)一一插入一颗Trie中,然后一一查询每个值。每次查询,尽量走与当前查询值在该位不同的边,以获得xor值的最大。

最终的答案即为所有查询结果的最大值。


// BZOJ 1954 ( POJ 3764 )#include <cstdio>#include <algorithm>#include <cstring>using namespace std; const int N=100000+5, M=N; struct Edge { int from, to, w, pre; }e[M*2]; int k, last[N], ch[N*30][2], sz, n, u, v, w, ans, d[N]; void ine(int x, int y, int w) { k++; e[k].from=x, e[k].to=y, e[k].pre=last[x], e[k].w=w; last[x]=k; } #define reg(i,x) for (int i=last[x]; i; i=e[i].pre)  #define rep(i,a,b) for (int i=a; i<=b; i++) #define dep(i,a,b) for (int i=a; i>=b; i--) #define read(x) scanf("%d", &x) #define fill(a,x) memset(a, x, sizeof(a)) void change(int x, int fa, int dis) { d[x]=dis; reg(i,x) { int y=e[i].to; if (y==fa) continue; change(y, x, dis^e[i].w); } } void init() { k=0; fill(last, 0); fill(d, 0); sz=1; fill(ch, 0); } void charen(int x, int *s) { rep(i,0,30) s[i]=0; int i=0; while (x>0) s[i++]=(x%2), x/=2; } int s[35]; void insert(int x) { int u=1; charen(x, s); dep(i,30,0) { if (!ch[u][s[i]]) { sz++; ch[sz][0]=ch[sz][1]=0; ch[u][s[i]]=sz; } u=ch[u][s[i]]; } } void search(int x) { charen(x, s); int u=1, t=0; dep(i,30,0)  if (ch[u][s[i]^1]) { t+=(1<<i); u=ch[u][s[i]^1]; } else u=ch[u][s[i]]; ans=max(ans, t); }int main(){   while (scanf("%d", &n)==1 && n) {init();rep(i,1,n-1) read(u), read(v), read(w), u++, v++, ine(u, v, w), ine(v, u, w);change(1, 0, 0);    ans=0;     rep(i,1,n) insert(d[i]);    rep(i,1,n) search(d[i]);    printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击