HDU4825/5536 [01 字典树/简单字典树更新]

Xor Sum

Time Limit: 1000 MS

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

Input

输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。

Output

对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。

Sample Input

2 3 2 3 4 5 1 5 4 1 4 6 5 6 3

Sample Output

Case #1: 4 3 Case #2: 4

给出n个数,m次查询,每次查询输出异或值最大的那个数。

01字典树,原来字典树还有这种操作。

从高位向低位创建一棵字典树,val记录字典树的节点所代表的数值,查询的时候从高位开始向低位查询,每次贪心找到异或值最大的,输出该节点所代表的数值。

#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 100000 + 10;
int ch[32*maxn][2];
 LL val[32*maxn];
int sz;
void init(){
     memset(ch[0], 0 ,sizeof(ch[0]));
     sz = 1;
 }
void insert_01tree(LL a){
     int u = 0;
     for(int i = 31; i >= 0; i--) {
         int c = ((a>>i)&1);
         if(!ch[u][c]){
             //新开节点,使得上一级的节点指向新开的节点
             memset(ch[sz], 0, sizeof(ch[sz])); val[sz]=0;
             ch[u][c] = sz++;
         }
         u = ch[u][c];
     }
     val[u] = a; //储存当前的值
}
LL query(LL a){
     int u = 0;
     for(int i = 31; i >= 0; i--){
         int c = ((a>>i)&1);
         if(ch[u][c^1]) u = ch[u][c^1];
         else u = ch[u][c];
     }
     return val[u];
 }
int main(int argc, char const *argv[])
 {
     int T;
     int Kcase = 0;
     scanf("%d", &T);
     while (T--) {
         LL a; init();
         int N, M;
         scanf("%d%d", &N, &M);
         for (int i = 0; i < N; i++) {
             scanf("%lld", &a);insert_01tree(a);
         }
         printf("Case #%d:
", ++Kcase);
         while (M--) {
             scanf("%lld", &a);
             printf("%lld
", query(a));
         }
     }
     return 0;
}

Chip Factory

题意:

给一个数组A,从A中找到两个数使得两个数的和和数组中的另外一个的异或最大

枚举每两个数,将它们从字典树上删去,再查找和他们异或和最大的,然后在把两个数加到字典树上。用一个数组num记录每个数在字典树上的贡献,删去一个数只要把它的贡献减去就可以了。

#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn = 1e5;
LL a[maxn], val[maxn];
int ch[maxn][2], num[maxn];
int sz = 1;
void insert_01tree(LL x) {
    int u = 0;
    for (int i = 32; i >= 0; i--) {
        int c = ((x>>i)&1);
        if (!ch[u][c]) {
            memset(ch[sz], 0, sizeof(ch[sz]));
            num[sz] = 0; val[sz] = 0;
            ch[u][c] = sz++;
        }
        u = ch[u][c]; num[u]++; 
    }
    val[u] = x;
}
void updata(LL x, int d) {
    int u = 0;
    for (int i = 32; i >= 0; i--) {
        int c = ((x>>i)&1);
        u = ch[u][c];
        num[u] += d;
    }
}
LL query(LL x) {
    int u = 0; 
    for (int i = 32; i >= 0; i--) {
        int c = ((x>>i)&1);
        if(num[ch[u][c^1]] and ch[u][c^1]) u = ch[u][c^1];
        else u = ch[u][c];
    }
    return val[u];
}
void init() {
    memset(ch[0], 0, sizeof(ch[0]));
    memset(val, 0, sizeof(val));
    memset(num, 0, sizeof(num));
    sz = 1;
}
int main(int argc, char const *argv[])
{
    int T;
    scanf("%d", &T);
    while (T--) {
        init();
        int N;
        LL maxx = 0;
        scanf("%d", &N);
        for (int i = 0; i < N; i++) 
            scanf("%lld", a+i), insert_01tree(a[i]);
        for (int i = 0; i < N; i++) {
            for (int j = i + 1; j < N; j++) {
                updata(a[i], -1); updata(a[j], -1);
                maxx = max(maxx ,(a[i]+a[j]) xor query(a[i]+a[j]));
                updata(a[i], 1); updata(a[j], 1);
            }
        }
        printf("%lld
", maxx);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cniwoq/p/7345302.html