zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    55   return 0;
    56 }

     

  • 相关阅读:
    如果你很忙,你一定在什么地方做错了!
    NOSQL介绍
    mysql 8.0.11 安装(windows)
    ORA-28547:(Navicat Premium连接oracle报错)
    线性筛法
    Luogu-P1020(导弹拦截)(DP,LIS ,二分优化)
    POJ
    HDU
    HDU-1024-Max Sum Plus Plus(DP)
    UVA-1625-Color Length(DP LCS变形)
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13750660.html
Copyright © 2011-2022 走看看