[SCU 4494] 双剑合并 (xor字典树)

SCU - 4494

给定两个序列,问从两个序列中各取一个值的异或和最大为多少



把 A序列中的数字看成一个二进制的 01串,然后存到 Trie树里

然后将 B序列的数字同样看成一个 01串,然后在 Trie树上从高位到低位贪心地查找

如果B序列中查找的 01串当前位为 0,则找 Trie树上为 1的子儿子

否则就只能走为 0的右儿子,反之亦然,然后往下走

时间复杂度 O(N)

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Pow2(a) (a*a)

const int maxn=1e6+10,nxt_siz=2;
struct Trie
{
    struct node
    {
        int chr,nxt[nxt_siz];
    } *trie;
    int siz;
    Trie(int size){trie=new node[size];memset(trie,0,sizeof(node)*size);siz=0;}
    ~Trie(){delete []trie;}
    void addstr(char*);
    int query(char*);
};
int N,M;
int inpt[2][maxn];
int pow2[32];
char _str[50];

void nts(int,char*);

int main()
{
    pow2[0]=1;
    for(int i=1; i<32; i++) pow2[i]=pow2[i-1]<<1;
    int T;
    scanf("%d", &T);
    for(int ck=1; ck<=T; ck++)
    {
        scanf("%d%d", &N, &M);
        Trie data(3*maxn);
        for(int i=0; i<N; i++)
        {
            scanf("%d", &inpt[0][i]);
            nts(inpt[0][i], _str);
            data.addstr(_str);
        }
        int ans=0;
        for(int i=0; i<M; i++)
        {
            scanf("%d", &inpt[1][i]);
            nts(inpt[1][i], _str);
            ans=max(ans, data.query(_str));
        }
        printf("%d\n", ans);
    }
    return 0;
}

void Trie::addstr(char *str)
{
    int len=strlen(str),np=0;
    for(int i=0; i<len; i++)
    {
        int ch=str[i]-‘0‘;
        if(trie[np].nxt[ch]) np=trie[np].nxt[ch];
        else
        {
            trie[np].nxt[ch]=++siz;
            np=siz;
            trie[np].chr=str[i];
        }
    }
}

int Trie::query(char *str)
{
    int res=0,np=0;
    for(int i=0; i<31; i++)
    {
        int now=str[i]-‘0‘;
        if(trie[np].nxt[now^1])
        {
            np=trie[np].nxt[now^1];
            res^=1<<(30-i);
        }
        else if(trie[np].nxt[now])
        {
            np=trie[np].nxt[now];
        }
    }
    return res;
}

void nts(int num, char *str)
{
    for(int i=30; i>=0; i--){str[i]=(num&1)+‘0‘;num>>=1;}
}
时间: 2024-10-13 14:19:31

[SCU 4494] 双剑合并 (xor字典树)的相关文章

ACM学习历程—HDU 5536 Chip Factory(xor &amp;&amp; 字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536 题目大意是给了一个序列,求(si+sj)^sk的最大值. 首先n有1000,暴力理论上是不行的. 此外题目中说大数据只有10组,小数据最多n只有100.(那么c*n^2的复杂度应该差不多) 于是可以考虑枚举i和j,然后匹配k. 于是可以先把所有s[k]全部存进一个字典树, 然后枚举s[i]和s[j],由于i.j.k互不相等,于是先从字典树里面删掉s[i]和s[j],然后对s[i]+s[j]这个

ACM学习历程—POJ 3764 The xor-longest Path(xor &amp;&amp; 字典树 &amp;&amp; 贪心)

题目链接:http://poj.org/problem?id=3764 题目大意是在树上求一条路径,使得xor和最大. 由于是在树上,所以两个结点之间应有唯一路径. 而xor(u, v) = xor(0, u)^xor(0, v). 所以如果预处理出0结点到所有结点的xor路径和,问题就转换成了求n个数中取出两个数,使得xor最大. 这个之前用字典树处理过类似问题. 代码: #include <iostream> #include <cstdio> #include <cst

HDU6191 Query on A Tree (01字典树+启发式合并)

题意: 给你一棵1e5的有根树,每个节点有点权,1e5个询问(u,x),问你子树u中与x异或最大的值是多少 思路: 自下而上启发式合并01字典树,注意合并时清空trie 线段树.字典树这种结构确定的数据结构,启发式合并的时候不需要考虑次序,复杂度都是nlogn 代码: 2200 / 10000ms , 60 / 128 M #include<iostream> #include<cstdio> #include<algorithm> #include<cmath&

HDU6191(01字典树启发式合并)

Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 801    Accepted Submission(s): 302 Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey

HDU 4825 Xor Sum(经典01字典树+贪心)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 1555    Accepted Submission(s): 657 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Ze

hdu5269 ZYB loves Xor I 异或,字典树

hdu5269  ZYB loves Xor I   异或,字典树 ZYB loves Xor I Accepts: 142 Submissions: 696 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 ZYB喜欢研究Xor,现在他得到了一个长度为nn的数组A.于是他想知道:对于所有数对(i,j)(i \in [1,n],j \in [1,n])(i,j)(i∈[1,n

2014百度之星资格赛—— Xor Sum(01字典树)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起

CODEVS1187 Xor最大路径 (字典树)

由于权值是在边上,所以很容易发现一个性质:d(x,y)=d(x,root) xor d(y,root). 因为有了这个性质,那么就很好做了.对于每一个点统计到root的距离,记为f 数组. 将f数组里的每个值插进按照二进制位插进字典树里面. 枚举每一个点,然后在字典树中搜索最大的xor值就可以了. Program CODEVS1187; const maxn=100008; type arr=record u,v,w,next:int64; end; type arr1=record next:

字典树-百度之星-Xor Sum

Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Input 输入包含若干组测试数