01Trie树--P4551 最长异或路径

一个定理:$a$-$root$的异或和^$b$-$root$的异或和=$a$-$b$的异或和

证明:$a$^$a_1$^$a_2$^……$root$^$root$^$b$^$b_1$^$b_2$^……

因为:$a$^$a$=0 0异或任何数为它本身,所以上述式子就等于$a$^$a_1$^$a_2$^……^$b$^$b_1$^$b_2$^……,就等于$a$-$b$的异或和

因此求两个点之间的路径的异或和=两个点到根节点的异或和的异或值,这两个值我们可以预处理维护出来

拆分成二进制后,从高位往低位加入Trie树中,枚举依次从$n$个点出发,能得到的最大的路径异或和

如何求最大的路径异或和???

如果高位为1,肯定比低位为1更优,所以我在Trie树中往下找的时候,最优的策略是本位0取1,本位1取0,如果不能取的话,那就……不取吧

代码实现:

 1、求每个点到根节点的异或和

1 void dfs(int now,int fa){
2   for (int i = head[now];i;i=ed[i].next){
3     int to=ed[i].to;
4     if (to==fa) continue;
5     dis[to]=dis[now]^ed[i].w;
6     dfs(to,now);
7   }
8 }

2、建Trie树: $x$&$i$可以求出$x$这个数拆分成2进制后,第$i$位是不是1

1 void build(int x,int root){
2   for (int i = (1<<30);i;i>>=1){
3     bool c=x&i;
4     if (!trie[root][c]) trie[root][c]=++cnt;
5     root=trie[root][c];
6   }
7 }

3、查询: 本位$c$取$c^1$,如果可取,跳到$c^1$,否则只能跳到$c$

1 int query(int root,int x){
2   int ans=0;
3   for(int i = (1<<30);i;i>>=1){
4     bool c=x&i;
5     if (trie[root][1^c]) ans+=i,root=trie[root][1^c];
6     else root=trie[root][c];
7   }
8   return ans;
9 }

完整代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 using namespace std;
 5 int n;
 6 const int maxn=1e6+10;
 7 int trie[maxn][5],head[maxn],tot,dis[maxn],cnt;
 8 struct node{
 9   int next,to,w;
10 }ed[maxn];
11 void add(int u,int to,int w){
12   ed[++tot].to=to;
13   ed[tot].w=w;
14   ed[tot].next=head[u];
15   head[u]=tot;
16 }
17 void dfs(int now,int fa){
18   for (int i = head[now];i;i=ed[i].next){
19     int to=ed[i].to;
20     if (to==fa) continue;
21     dis[to]=dis[now]^ed[i].w;
22     dfs(to,now);
23   }
24 }
25 void build(int x,int root){
26   for (int i = (1<<30);i;i>>=1){
27     bool c=x&i;
28     if (!trie[root][c]) trie[root][c]=++cnt;
29     root=trie[root][c];
30   }
31 }
32 int query(int root,int x){
33   int ans=0;
34   for(int i = (1<<30);i;i>>=1){
35     bool c=x&i;
36     if (trie[root][1^c]) ans+=i,root=trie[root][1^c];
37     else root=trie[root][c];
38   }
39   return ans;
40 }
41 int u,v,w;
42 int main(){
43   scanf ("%d",&n);
44   for (int i = 1;i <= n-1;i++){
45     scanf ("%d%d%d",&u,&v,&w);
46     add(u,v,w);add(v,u,w);
47   }
48   dfs(1,0);
49   int ans=0;
50   for (int i = 1;i <= n;i++) build(dis[i],0);
51   for (int i = 1;i <= n;i++){
52     ans=max(ans,query(0,dis[i]));
53   }
54   printf("%d\n",ans);
55   return 0;
56 }

 

posted @ 2020-09-29 17:12  小又又  阅读(138)  评论(0编辑  收藏  举报