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

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

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

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

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

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

2016.1.13更新:啊啊啊刚刚开通了权限账号,立刻补番,结果。。BZOJ要不要这么坑!。。在HINT的一个不起眼的小角落里,“注意:结点下标从1开始到N....”。。导致WA了两次… 简直丧病。。

 1 // BZOJ 1954 ( POJ 3764 )
 2 
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <cstring>
 6 using namespace std;
 7 
 8  const int N=100000+5, M=N;
 9 
10  struct Edge {
11      int from, to, w, pre;
12  }e[M*2];
13 
14  int k, last[N], ch[N*30][2], sz, n, u, v, w, ans, d[N];
15 
16  void ine(int x, int y, int w) {
17      k++;
18      e[k].from=x, e[k].to=y, e[k].pre=last[x], e[k].w=w;
19      last[x]=k;
20  }
21  #define reg(i,x) for (int i=last[x]; i; i=e[i].pre) 
22 
23  #define rep(i,a,b) for (int i=a; i<=b; i++)
24  #define dep(i,a,b) for (int i=a; i>=b; i--)
25  #define read(x) scanf("%d", &x)
26  #define fill(a,x) memset(a, x, sizeof(a))
27 
28  void change(int x, int fa, int dis) {
29      d[x]=dis;
30      reg(i,x) {
31          int y=e[i].to;
32          if (y==fa) continue;
33          change(y, x, dis^e[i].w);
34      }
35  }
36 
37  void init() { k=0; fill(last, 0); fill(d, 0); sz=1; fill(ch, 0); }
38 
39  void charen(int x, int *s) {
40      rep(i,0,30) s[i]=0;
41      int i=0;
42      while (x>0) s[i++]=(x%2), x/=2;
43  }
44 
45  int s[35];
46  void insert(int x) {
47      int u=1;
48      charen(x, s);
49      dep(i,30,0) {
50          if (!ch[u][s[i]]) {
51              sz++;
52              ch[sz][0]=ch[sz][1]=0;
53              ch[u][s[i]]=sz;
54          }
55          u=ch[u][s[i]];
56      }
57  }
58 
59  void search(int x) {
60      charen(x, s);
61      int u=1, t=0;
62      dep(i,30,0) 
63          if (ch[u][s[i]^1]) {
64              t+=(1<<i);
65              u=ch[u][s[i]^1];
66          }
67          else u=ch[u][s[i]];
68      ans=max(ans, t);
69  }
70 
71 int main()
72 {   
73     while (scanf("%d", &n)==1 && n) {
74         init();
75         rep(i,1,n-1) read(u),read(v),read(w),u++,v++,ine(u, v, w),ine(v, u, w); 
76      // BZOJ上提交的话要把u++ v++去掉……
77 
78         change(1, 0, 0);
79 
80         ans=0; 
81         rep(i,1,n) insert(d[i]);
82         rep(i,1,n) search(d[i]);
83 
84         printf("%d\n", ans);
85     }
86 
87     return 0;
88 }
89 

 

posted @ 2015-12-10 20:55  Armeria  阅读(238)  评论(0编辑  收藏  举报