POJ 3764 (异或+字典树)

早就听过用字典树求异或最大值,然而没做过。发现一碰到异或的题就GG,而且因为以前做过的一道类似的题(事实上并不类似)限制了思路,蠢啊= =。

题意:一棵带权的树,求任意两点间路径异或的最大值。

题解:设xor(a,b)是求a,b间路径的异或值,那么xor(a,b)=xor(root,a)^xor(root,b)。因为如果LCA(a,b)==root时结论显然成立,不然的话就会有重复走过的部分,但是异或有性质x^x=0,所以LCA(a,b)!=root结论依然成立。

这样题目就很简单了。对每一个xor(root,i)(0<i<n)建立trie,因为每个数转成二进制都是一个01组成的字符串,用来建立trie。然后对每一个xor(root,i)在trie查询最大值就好了。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#define pk printf("lalala");
#define ppp(x) printf("%d
", x)
using namespace std;
#define PI acos(-1.0)
#define EXP exp(1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))


const int KIND = 2;
const int MAXN = 5000005;
const int N = 100005;
int cnt_node;

struct node{
    node* nt[KIND];
    void init(){
        memset(nt, 0, sizeof(nt));
    }
} Heap[MAXN];
node *root;
int Xor[N];

inline node* new_node()
{
    Heap[cnt_node].init();
    return &Heap[cnt_node++];
}

void insert(node* root, int *str)
{
    for(int i = 0; i <= 30; ++i){
        int ch = str[i];
        if(root->nt[ch] == NULL)
            root->nt[ch] = new_node();
        root = root->nt[ch];
    }
}

int count(node* root, int *str)
{
    int ans = 0;
    for(int i = 0; i <= 30; ++i){
        int ch = str[i];
        int need = (ch ^ 1);
        if(root->nt[need] == NULL) {
            root = root->nt[ch];
        } else {
            root = root->nt[need];
            ans += (1 << (30 - i));
        }
    }
    return ans;
}

struct Edge {
    int to;
    int w;
    int next;
} edge[N * 2];

int cnt_edge;
int head[N];

void add_edge(int u, int v, int w)
{
    edge[cnt_edge].to = v;
    edge[cnt_edge].w = w;
    edge[cnt_edge].next = head[u];
    head[u] = cnt_edge++;
}

void dfs(int u, int fa, int val)
{
    Xor[u] = val;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        int w = edge[i].w;
        if (v == fa) continue;
        dfs(v, u, val^w);
    }
}


int str[N][40];

int main()
{
    int n;
    while (~scanf("%d",&n)) {
        clr(head, -1);
        cnt_edge = 0;
        cnt_node = 0;
        root = new_node();
        int u, v, w;
        for (int i = 1; i < n; ++i) {
            scanf("%d%d%d",&u, &v, &w);
            add_edge(u, v, w);
            add_edge(v, u, w);
        }
        dfs(0, -1, 0);
        //for (int i = 0; i < n; ++i) printf("%d ", Xor[i]); printf("
");
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int idx = 0;
            for (int b = 30; b >= 0; --b) {
                str[i][idx++] = Xor[i] & (1 << b) ? 1 : 0;
            }
            //for (int j = 0; j < idx; ++j) printf("%d ", str[i][j]); printf("
");
            insert(root, str[i]);
        }
        for (int i = 0; i < n; ++i) {
            ans = max(ans, count(root, str[i]));
        }
        printf("%d
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wenruo/p/5502304.html