zoukankan      html  css  js  c++  java
  • 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;
    }

     

     

  • 相关阅读:
    【万里征程——Windows App开发】使用华丽丽的字体
    【万里征程——Windows App开发】SemanticZoom视图切换
    用Alt码打出Pi以及各式各样的符号
    3行代码列出硬盘上所有文件及文件夹
    【万里征程——Windows App开发】ListView&GridView之分组
    【万里征程——Windows App开发】ListView&GridView之添加数据
    从头认识js-js中的对象
    js中如何判断属性是对象实例中的属性还是原型中的属性
    从头认识js-HTML中使用JavaScript
    从头认识js-js的发展历史
  • 原文地址:https://www.cnblogs.com/shinecheng/p/3623892.html
Copyright © 2011-2022 走看看