hdu5269 数据结构Trie

Memphis loves xor very musch.Now he gets an array A.The length of A is n.Now he wants to know the sum of all (lowbit(Ai xor Aj)) (i,j∈[1,n])

We define that lowbit(x)=2k,k
is the smallest integer satisfied ((x and 2k)>0)

Specially,lowbit(0)=0

Because the ans may be too big.You just need to output ans mod
998244353

Input

Multiple test cases, the first line contains an integer T(no more than 10), indicating the number of cases. Each test case contains two lines

The first line has an integer n

The second line has n integers A1,A2....An

n∈[1,5?104],Ai∈[0,229]

Output

For each case, the output should occupies exactly one line. The output format is Case #x: ans, here x is the data number begins at 1.

Sample Input

2
5
4 0 2 7 0
5
2 6 5 4 0

Sample Output

Case #1: 36

Case #2: 40
当A xor B的答案为2p时,A和B表示成二进制数后末p?1位肯定相同
于是我们维护一颗字母树,将每个数表示成二进制数后翻转可以下,插入字母树
统计答案时,我们找出Ai的二进制数翻转后在字母树上的路径,对于路径上每个点x,设他走的边是v,且当前为第k位,则和他xor后lowbit为2k的数的个数为trans(x,v^1)的子树大小。
trans(x,v)表示字母树上在结点x,走连出去的字母为v的边到达的结点

//
//  main.cpp
//  bc44_B
//
//  Created by Fangpin on 15/6/13.
//  Copyright (c) 2015年 FangPin. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct Trie{
    int v;
    Trie *next[2];
    Trie(){next[0]=next[1]=NULL;v=1;}
}*rt;
const int M=998244353;

void build(){
    rt=new Trie;
}

int a[31],f[31];
long long ans=0;

void insert(){
    Trie *p=rt,*q;
    for(int i=0;i<31;++i){
        if(p->next[a[i]^1]!=NULL)
            ans=(ans+p->next[a[i]^1]->v*f[i])%M;
        if(p->next[a[i]]==NULL){
            q=new Trie;
            p->next[a[i]]=q;
            p=q;
        }
        else{
            p=p->next[a[i]];
            ++p->v;
        }
    }
}

void solve(Trie *root){
    for(int i=0;i<2;++i){
        if(root->next[i]!=NULL)
            solve(root->next[i]);
    }
    delete root;
}

void init(){
    f[0]=1;
    for(int i=1;i<31;++i){
        f[i]=f[i-1]<<1;
    }
}

int main(int argc, const char * argv[]) {
    // insert code here...
    int t;
    init();
    cin>>t;
    for(int ca=1;ca<=t;++ca){
        int n;
        scanf("%d",&n);
        build();
        ans=0;
        for(int i=0;i<n;++i){
            int tem;
            scanf("%d",&tem);
            for(int j=0;j<31;++j){
                a[j]=(tem>>j)&1;
            }
            insert();
        }
        solve(rt);
        cout<<"Case #"<<ca<<": "<<(ans*2)%M<<endl;
    }
    return 0;
}

时间: 2024-10-10 22:37:45

hdu5269 数据结构Trie的相关文章

【学习总结】数据结构-Trie/前缀树/字典树-及其最常见的操作

Trie/前缀树/字典树 Trie (发音为 "try") 或前缀树是一种树数据结构,用于检索字符串数据集中的键. 一种树形结构,是一种哈希树的变种. 典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高. 应用: 自动补全 END 原文地址:https://www.cnblogs.com/anliux/p/12590368.html

基本数据结构①——trie树

RT trie树是一种用于实现字符串的快速检索的树结构:大该是每个节点都有若干个指向字符的指针:如图: 好像看不清,不过没多大事: 然后trie树支持两个操作:插入,查找: 先放代码 struct data p=trie[p].son[ch]; } trie[p].have=true; } int f(char *s) { int len=strlen(s),p=0; for(int k=0;k<len;++k) { int ch=s[k]-'a'; if(!trie[p].son[ch]) r

数据结构~trie树(字典树)

1.概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. 我理解字典树是看了这位大佬博客.还不了解字典树的可以先进去学习一下 https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html 还有这个讲了下为什么用字典树,和其他的相比优缺点在哪 https://www.cnblogs.com/Allen-rg/p/7128518.html 现在来个题来更进一

【hdoj】1251 统计难题 【数据结构-Trie树裸题】

传送门:统计难题 题意: 字典树裸题. 分析 字典树板子,但是这题需要注意一点. 关于字典树的只是可以参考hihocoder hiho一下 第二周 用G++提交会爆内存(Memory Limit Exceeded),用c++提交可以AC. G++ 与 C++提交的区别 参考:OJ中的语言选项里G++ 与 C++的区别 C++是一门计算机编程语言,而G++则是C++的编译器. 选择C++意味着你将使用C++最标准的编译方式,也就是ANSI C++编译. 选择G++则意味这你使用GNU项目中适用人群

基本数据结构—Trie

理论知识与功能 定义 Trie(字典树),用于实现字符串的快速检索.其每个节点都含有若干个字符指针. 例如我在字典树里插入"abc","ac",那么就会生成一个这样丑陋的东西. 好吧是我的图画的丑陋 初始化 一棵空的Trie仅包含一个根节点,那么他的指针自然也指向空. 注:因为Trie运用在检索字符串,所以此处指针指代字符指针. 插入 对于需要插入的一个字符串S而言,我们令指针P指向根节点.然后依次扫描P中的每个字符c 1.若P的c字符指针指向空(即没有这个节点),

数据结构——trie树(字典树)

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高. 模板题: 代码 #include<iostream> using namespace std; const int N = 200010; //用来存放子节点,idx是已经使用的结点下标 int son[N][26],idx;

B树、Trie树详解

查找(二) 散列表 散列表是普通数组概念的推广.由于对普通数组可以直接寻址,使得能在O(1)时间内访问数组中的任意位置.在散列表中,不是直接把关键字作为数组的下标,而是根据关键字计算出相应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们需要面对两个或多个键都会散列到相同的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探测法. 散列表是算法在时间和空间上作出权衡的经典例子. 如果没有内存限制,我们可以直接

查找(二)简单清晰的B树、Trie树具体解释

查找(二) 散列表 散列表是普通数组概念的推广.因为对普通数组能够直接寻址,使得能在O(1)时间内訪问数组中的任何位置.在散列表中,不是直接把keyword作为数组的下标,而是依据keyword计算出对应的下标. 使用散列的查找算法分为两步.第一步是用散列函数将被查找的键转化为数组的一个索引. 我们须要面对两个或多个键都会散列到同样的索引值的情况.因此,第二步就是一个处理碰撞冲突的过程,由两种经典解决碰撞的方法:拉链法和线性探測法. 散列表是算法在时间和空间上作出权衡的经典样例. 假设没有内存限

poj2513 Colored Sticks (欧拉通路+Trie树+并查集)

D - Colored Sticks Crawling in process... Crawling failed Time Limit:5000MS     Memory Limit:128000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2513 Appoint description: System Crawler (2016-05-05) Description You are given a bunch