HRBUST 2072:萌萌哒十五酱的礼物~(树,字典树)

题意:n个点的一棵树,树的边上有权值。一条路径的权值定义成这条路径上所有边的权值的xor。问所有路径的最大权值是多少。

思路:

首先,树上任意两点之间的路可以表示成 这两点到根节点的路- 其最近公共祖先到根节点的路*2.那么这里如果是用xor操作,重复的那部分正好就没了。

深搜一边,得出所有点到根节点的权值,这样问题就边成了n个数字,将其中两个xor,问得到的最大值是什么。

然后这里我卡住了……实际上做法非常……

用字典树记录所有这些树(二进制),然后对每一个数,去找现在存在的和它xor之后答案最大的那个数。暴力完n个数就得到答案= =……

坑:深度太深爆栈了。只能自己写。用栈模拟了递归,但感觉又不像是深搜又不像是广搜……兼有两个特点,姑且称为广深搜吧……

新品种:广深搜

实现方法:用栈代替队列实现广搜,就出现这奇特的品种。

优点:代替深搜防爆栈,代替广搜省内存。

缺点:用之前谨慎……看看问题是不是能用这种方法解决。

代码:

/*
* 树上两点之间路径 = 两点到根的路径 - 最近公共祖先到根的路径*2
* 字典树,暴力每个数,找其配对的尽量大的数
* 坑点:dfs 深搜爆栈, 字典树节点要开到至少15倍……(估计最大32倍吧)
*/
#include <cstdio>
#include <cstring>
#define N 100010

struct Graph{
    struct Edge{
        int to, next, c;
    }e[N<<2];
    int head[N];
    int p;
    void init() {
        memset(head, -1, sizeof(head));
        p = 0;
    }
    void add(int u, int v, int c) {
        e[p].to = v;
        e[p].c = c;
        e[p].next = head[u];
        head[u] = p++;
    }
}g;

int dis[N];

struct Dictree{
    struct Node {
        int val[2];
        void init() {
            memset(val, -1, sizeof(val));
        }
    }node[N<<4]; // 够么?
    int p;
    void init() {
        node[0].init();
        p = 1;
    }
    void insert(int x) {
        int now = 0;
        for (int i = 30; i >= 0; i--) {
            int k = ((x>>i)&1);
            if (node[now].val[k] == -1) {
                node[p].init();
                node[now].val[k] = p++;
            }
            now = node[now].val[k];
        }
    }
    int find(int x) {
        int now = 0;
        int ans = 0;
        for (int i = 30; i >= 0; i--) {
            int k = ((x>>i)&1);
            if (node[now].val[k] == -1) {
                k = !k;
            }
            ans = ((ans<<1)|k);
            now = node[now].val[k];
        }
        return ans;
    }

}dict;

int stk[N];
void dfs(int now) {
    int top = 0;
    stk[top++] = now;
    while (top) {
        now = stk[--top];
        dict.insert(dis[now]);
        for (int i = g.head[now]; i != -1; i = g.e[i].next) {
            int to = g.e[i].to;
            int c = g.e[i].c;
            if (dis[to] == -1) {
                dis[to] = dis[now]^c;
                stk[top++] = to;
            }
        }
    }
}

int main() {
    int n;
    while (scanf("%d", &n) != EOF ){
        g.init();
        for (int i = 0; i < n-1; i++) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            g.add(a,b,c);
            g.add(b,a,c);
        }
        memset(dis, -1, sizeof(dis)); //会不会^出-1?
        dis[1] = 0;
        dict.init();
        dfs(1);
        int maxans = 0;
        for (int i = 1; i <= n; i++) {
            int ans = dis[i]^dict.find(~dis[i]);
            if (maxans < ans) maxans = ans;
        }
        printf("%d
", maxans);
    }
    return 0;
}

 

 

原文地址:https://www.cnblogs.com/shinecheng/p/3623892.html