poj 3764 The xor-longest Path (Trie树)

Description

In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p:

(you ren kan ti ma? xian ran mei you. na wo jiu bu tie tu le.)
⊕ is the xor operator.

We say a path the xor-longest path if it has the largest xor-length. Given an edge-weighted tree with n nodes, can you find the xor-longest path?  

Input

The input contains several test cases. The first line of each test case contains an integer n(1<=n<=100000), The following n-1 lines each contains three integers u(0 <= u < n),v(0 <= v < n),w(0 <= w < 2^31), which means there is an edge between node u and v of length w.

Output

For each test case output the xor-length of the xor-longest path.

Sample Input

4
0 1 3
1 2 4
1 3 6

Sample Output

7

题意

给出 1 棵树,询问树链上的最大连续异或和。

题解

利用异或和的性质可以得出求出dis(前缀异或和)后可以用神奇的性质求解答案(……)。这里用了指针和数组两种方法写的trie树。

代码1

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 400010;

int n, num, ans, tot, dis[N], head[N];

struct Trie {
    int child[2];
    void newnode() {
        child[0] = 0, child[1] = 0;
    }
} trie[N << 3];

struct Edge {
    int v, next, w;
} edge[N << 3];

void add(int u, int v, int w) {
    num ++;
    edge[num].v = v;
    edge[num].w = w;
    edge[num].next = head[u];
    head[u] = num;
}

void insert(int now) {
    int root = 0, p;
    for(int i = 30; i >= 0; i --) {
        if(now & (1 << i)) p = 1;
        else p = 0;
        if(! trie[root].child[p]) {
            trie[root].child[p] = ++ tot;
            trie[tot].newnode();
        }
        root = trie[root].child[p];
    }
}

void dfs(int u, int f, int w) {
    dis[u] = w;
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if(f == v) continue;
        dfs(v, u, w^edge[i].w);
    }
}

int query(int now) {
    int p, ans = 0, root = 0;
    for(int i = 30; i >= 0; i --) {
        if(now & (1 << i)) p = 0;
        else p = 1;
        if(trie[root].child[p]) {
             ans |= (1 << i);
             root = trie[root].child[p];
        }
        else root = trie[root].child[! p];
    }
    return ans;
}

void clear() {
    trie[0].newnode();
    ans = -1, num = 0, tot = 0;
    memset(dis, 0, sizeof(dis));
    memset(trie, 0, sizeof(trie));
    memset(head, 0, sizeof(head));
}

int main() {
    while(scanf("%d", &n) != EOF){
        clear();
        for(register int i = 1; i < n; i ++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        dfs(0, -1, 0);
        for(register int i = 0; i < n; i ++) {
            ans = max(ans, query(dis[i]));
            insert(dis[i]); 
        }
        printf("%d\n", ans);
    }
    return 0;
}

代码2

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1000010;

int n, num, ans = 0, dis[N], head[N << 3];

struct Trie {
    Trie *child[2];
} pool[N << 3], *tail = pool, *root;

struct Edge {
    int v, next, w;
} edge[N << 3];

Trie *newtrie() {
    Trie *node = ++ tail;
    node -> child[0] = NULL, node -> child[1] = NULL;
    return node;
}

void add(int u, int v, int w) {
    num ++;
    edge[num].v = v;
    edge[num].w = w;
    edge[num].next = head[u];
    head[u] = num;
}

void insert(int now) {
    Trie *node = root;
    int p;
    for(int i = 30; i >= 0; i --) {
        if(now & (1 << i)) p = 1;
        else p = 0;
        if(node -> child[p] == NULL)
            node -> child[p] = newtrie();
        node = node -> child[p];
    }
}

void dfs(int u, int f, int w) {
    dis[u] = w;
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if(f == v) continue;
        dfs(v, u, w^edge[i].w);
    }
}

int query(int now) {
    Trie *node = root;
    int ans = 0, p;
    for(int i = 30; i >= 0; i --) {
        if(now & (1 << i)) p = 0;
        else p = 1;
        if(node -> child[p] != NULL) {
             ans |= (1 << i);
             node = node -> child[p];
        }
        else if(node -> child[p ^ 1] != NULL)
            node = node -> child[p ^ 1];
        else return 0;
    }
    return ans;
}

void clear() {
    delete tail;
    delete root;
    ans = 0, num = 0;
    memset(dis, 0, sizeof(dis));
    memset(head, 0, sizeof(head));
}

int main() {
    while(scanf("%d", &n) != EOF){
        clear();
        root = newtrie();
        for(register int i = 1; i < n; i ++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        dfs(0, -1, 0);
        for(register int i = 0; i < n; i ++) {
            ans = max(ans, query(dis[i]));
            insert(dis[i]); 
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值