• 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;
    }

     

     

  • 相关阅读:
    彻底理解cookie,session,token.md
    13Gin中使用jwt
    qstat f队列状态是au和s,如何恢复
    shell三剑客
    mysql根据俩个字段之差进行区间分组
    运行jnlp文件
    mount o后面参数含义
    Linux常用命令
    java VelocityEngine 属性key值得组成说明
    Linux 基本命令 sed
  • 原文地址:https://www.cnblogs.com/shinecheng/p/3623892.html
Copyright © 2020-2023  润新知