算法学习——trie树求最大异或对

这道题目很难想到是字典树,如果不是放在字典树单元的话.
简单来说,一个整数,是可以转化成为一个32位的二进制数,而也就可以变成长度为32位的二进制字符串.
既然如此的话,根据二进制异或的原理:不同得1,否则得0,假如想让这个数字最大,我们就需要使得这个数的二进制表示中从左往右尽可能的取到1,也就是尽量的使得1最多。

那么我们可以这么做:

每一次检索的时候,我们都走与当前AiAi这一位相反的位置走,也就是让Xor值最大,如果说没有路可以走的话,那么就走相同的路.

详情见代码:

#include<iostream>
using namespace std;

const int N = 100010;

int s[N*32][2],idx;
int cnt[N*32];
int t[N],res;

void insert(int x){
    int p = 0;
    for(int i = 30;i >= 0 ;i -- ){
        //取x从二进制上右往左第i位上的数
        int n = x >> i & 1;
        //先判断该子节点是否存在
        if(!s[p][n]){
            //若不存在的话就创建
            s[p][n] = ++ idx;
            p = s[p][n];
        }else{
            //若存在的话就继续
            p = s[p][n];
        }
    }
}

int query(int x){
    int res = 0;
    int p = 0;
    for(int i = 30; i>=0 ; i --){
        //取x从二进制上右往左第i位上的数
        int n = x >> i & 1;
        //先判断是否存在和n不同的子节点
        if(s[p][!n]){
            //若存在则选则此节点;并且将对应位置二进制异或的值加到结果里
            res += 1 << i;
            p = s[p][!n];
        }else{
            //若不存在则选择存在的子节点
            p = s[p][n];
        }
    }
    return res;
}

int main(){
    int n;
    cin>>n;
    for(int i = 0 ; i < n ;i ++ ){
        cin>>t[i];
        insert(t[i]);
    }
    for(int i = 0 ; i < n ; i ++){
        res = max(res,query(t[i]));
    }
    cout<<res<<endl;

    return 0;
}

原文地址:https://www.cnblogs.com/Flydoggie/p/12268942.html

时间: 2024-10-12 03:18:26

算法学习——trie树求最大异或对的相关文章

利用Trie树求多个字符串编辑距离的进一步优化

1.引言 题目的意思应该是:在一个给定的字典中,求与给定的字符串的编辑距离不大于2的所有的单词.原先写过两片关于此问题的文章,那两片篇章文章给出两种解决思路:其一是暴力求解法,这种方法最容易想到.就是将词典中的词一一与给定的字符串计算编辑距离,不大于2的输出,大于2的舍弃,这种方法思路简单但是很费时间.其二根据词典中这些词之间的编辑距离建立一个以单词为节点的Trie树,遍历的时候,通过计算根节点与给定字符串的编辑距离就可以排除掉一部分分支了,然后继续计算该字符串与剩余的分支的根的编辑距离,继续排

算法学习 - 表达树的建立(后缀表达式法),树的先序遍历,中序遍历,后序遍历

表达树就是根据后缀表达式来建立一个二叉树. 这个二叉树的每个叶子节点就是数,真祖先都是操作符. 通过栈来建立的,所以这里也会有很多栈的操作. 树的先序遍历,中序遍历,后序遍历的概念我就不讲了,不会的自行百度,不然也看不懂我的代码. 下面是代码: // // main.cpp // expressionTree // // Created by Alps on 14-7-29. // Copyright (c) 2014年 chen. All rights reserved. // #includ

算法复习——trie树(poj2001)

题目: 题目描述 给出 n 个单词(1<=n<=1000),求出每个单词的非公共前缀,如果没有,则输出自己. 输入格式 输入 N 个单词,每行一个,每个单词都是由 1-20 个小写字母构成. 输出格式 输出 N 行,每行由一个空格的两部分,第一部分是输入的单词,第二部分是该单词在所有单词中的非公共前缀,如果没有,则输出自己. 样例数据 1 输入 [复制] carbohydrate cart carburetor caramel caribou carbonic cartilage carbon

13-看图理解数据结构与算法系列(Trie树)

Trie树 Trie树,是一种搜索树,也称字典树或单词查找树,此外也称前缀树,因为某节点的后代存在共同的前缀.它的key都为字符串,能做到高效查询和插入,时间复杂度为O(k),k为字符串长度,缺点是如果大量字符串没有共同前缀时很耗内存.它的核心思想就是减少没必要的字符比较,使查询高效率,即用空间换时间,再利用共同前缀来提高查询效率. Trie树特点 根节点不包含字符,其他节点每个节点只包含一个字符. 从根节点到某一节点经过路径的字符连起来即为该节点对应的字符串. 每个节点的所有子节点字符都不相同

POJ 3764 The xor-longest Path 字典树求最大异或

题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大 把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v) 则f(u, v) = f(1, u) ^ f(1, v) 这是显然的 其中f(1, i)是可以再O(n)内处理出来 然后就是在一个数组内,找两个数异或值最大 然后就可以用字典树来搞 每个数变成01串,  然后插入字典树, 第30位在最前,然后29,依次到0位 就建立成了一个深度为31的字典树 对于一个询问,在字典树上找,就是尽量找跟其相反的路径.

算法学习——利用归并排序求逆序对的数量

首先明白逆序对的定义,逆序对就是数组中两个元素前大后小,我们就称这两个元素为一组逆序对. 接着看题目:  我们利用分治的思想,将区间一分为二,然后得到了逆序对的存在情况共三种: 1.两个元素都在左侧区间. 2.两个元素都在右侧区间. 3.两个元素一个在左,一个在右. 那么很明显我们分治的去解决这个问题,就得到解法, 1.将区间划分成左右两个区间 2.递归左右两个区间 3.统计逆序对数量(1)+(2) 4.计算逆序对数量(3) 5.返回相应的结果. 那么问题来了,逆序对(1)(2)的情况都很容易理

算法模板——Trie树

实现功能——实现对于不同字符串以及之前出现过的字符串的识别,对于单个长度为L的字符串,复杂度为O(L); 代码不难懂,直接上(在识别字符串方面,个人觉得其好处远远大于hash识别——1.理论上都是O(L) 2.哈希弄不好撞车撞一大串,尤其是哈希策略不太好的时候,而这个绝对不可能撞,严格的O(L) 3.这个代码真心短,一点也不比hash长,只要你链表还会用) 1 type 2 pp=^nod; 3 nod=record 4 ex:longint; 5 next:array[char] of pp;

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密