zoukankan      html  css  js  c++  java
  • HDU 4757 Tree 可持久化字典树

    Tree

    Time Limit: 20 Sec

    Memory Limit: 256 MB

    题目连接

    http://acm.hdu.edu.cn/showproblem.php?pid=4757

    Description

    Zero and One are good friends who always have fun with each other. This time, they decide to do something on a tree which is a kind of graph that there is only one path from node to node. First, Zero will give One an tree and every node in this tree has a value. Then, Zero will ask One a series of queries. Each query contains three parameters: x, y, z which mean that he want to know the maximum value produced by z xor each value on the path from node x to node y (include node x, node y). Unfortunately, One has no idea in this question. So he need you to solve it.

    Input

    There are several test cases and the cases end with EOF. For each case:

    The first line contains two integers n(1<=n<=10^5) and m(1<=m<=10^5), which are the amount of tree’s nodes and queries, respectively.

    The second line contains n integers a[1..n] and a[i](0<=a[i]<2^{16}) is the value on the ith node.

    The next n–1 lines contains two integers u v, which means there is an connection between u and v.

    The next m lines contains three integers x y z, which are the parameters of Zero’s query.

    Output

      For each query, output the answer.

    Sample Input

    3 2
    1 2 2
    1 2
    2 3
    1 3 1
    2 3 2

    Sample Output

    3
    0

    HINT

    题意

    给你一棵树,每个点有一个权值

    Q次询问,每次询问你在(x,y)这条链上的点与c异或的最大值是多少

    题解:

    可持久化字典树,对于每个点都保存一棵可持久化字典树

    每个字典树先从他的fa那儿复制过来,然后再将自己的这个字符串插入进去就好了

    可持久化字典树模板:http://www.cnblogs.com/qscqesze/p/5032334.html

    代码:

    #include<iostream>
    #include<stdio.h>
    #include<vector>
    #include<cstring>
    using namespace std;
    
    #define maxn 100005
    
    int w[maxn],n,q;
    vector<int> E[maxn];
    int root[maxn];
    // 使用前调用初始化函数 init() 同时 root[0] = 0;
    struct Trie_Persistent
    {
        const static int LetterSize = 5; // 字符集大小
        const static int TrieSize = 20 * ( 1e5 + 50); // 可能的所有节点总数量
        int tot; // 节点总数
    
        //节点类型
        struct node
        {
            int ptr[LetterSize]; // trie_node_ptr[]
            int cnt[LetterSize]; // 维护字符集数目
        }tree[TrieSize];
    
        // 获取字符集哈希编号 , 必须在 [0 , LetterSize) 之内
        inline int GetLetterIdx(int c){return c - 'a';}
    
        // 插入字符串 str , 上一个副本是 f
        /*
        int insert(const char * str ,int f){
            int len = strlen( str );
            int res = tot++; // 建立虚拟根结点
            tree[res] = tree[f]; // 初始化
            int cur = res; // 当前指针
            for(int i = 0 ; i < len ; ++ i){
                int idx = GetLetterIdx( str[i] ); // 获取字符编号
                int p = tot ++ ;  // 创建下一个虚拟节点
                tree[cur].cnt[idx] ++ ;
                tree[cur].ptr[idx] = p;
                f = tree[f].ptr[idx]; // 上一个副本的指针更新
                tree[p] = tree[f];  // updata information;
                cur = tree[cur].ptr[idx]; // updata ptr
            }
            return res;
        }
        */
    
        int insert(int t,int f){
            int str[30];
            for(int i = 15 ; i >= 0 ; -- i){
                if ( t >> i & 1) str[15 - i] = 1;
                else str[15 - i] = 0;
            }
            int res = tot++; // 建立虚拟根结点
            tree[res] = tree[f]; // 初始化
            int cur = res; // 当前指针
            for(int i=0;i<16;i++)
            {
                int idx = str[i] ; // 获取字符编号
                int p = tot ++ ;  // 创建下一个虚拟节点
                tree[cur].cnt[idx] ++ ;
                tree[cur].ptr[idx] = p;
                f = tree[f].ptr[idx]; // 上一个副本的指针更新
                tree[p] = tree[f];  // updata information;
                cur = tree[cur].ptr[idx]; // updata ptr
            }
            return res;
        }
    
        // 在 [l ,r] 副本中查找字符串str
        // 参数带入( str , root[l-1] , root[r])
        int find(int t , int l ,int r){
    
            int str[30];
            for(int i = 15 ; i >= 0 ; -- i){
                if ( t >> i & 1) str[15 - i] = 1;
                else str[15 - i] = 0;
            }
            int ans = 0;
            for(int i = 0 ; i < 16 ; ++ i){
                int idx = str[i]^1 ; // 获取字符Hash
                int cnt = tree[r].cnt[idx] - tree[l].cnt[idx];
                if(!cnt)
                    idx = idx^1;
                else
                    ans|=(1<<(15-i));
                l = tree[l].ptr[idx];
                r = tree[r].ptr[idx];
            }
            return ans;
        }
    
        void init(){tot = 1;for(int i = 0 ; i < LetterSize ; ++ i) tree[0].ptr[i] = 0 , tree[0].cnt[i] = 0; }    // 虚拟节点
    
    }trie;
    int lca[maxn][24];
    int deep[maxn];
    void init(int n)
    {
        trie.init();
        root[0]=0;
        for(int i=0;i<=n;i++)
        {
            E[i].clear();
            w[i]=0;
            root[i]=0;
        }
        for(int i = 1 ; i <= n ; ++ i)
            for(int j = 0 ; j <= 20 ; ++ j)
                lca[i][j] = 0;
    }
    int querylca(int u ,int v){
        if(deep[u] < deep[v]) swap( u , v );
        for(int i = 20 ; i >= 0 ; --i) if(deep[u] - (1 << i) >= deep[v]) u = lca[u][i];
        if( u == v ) return u;
        for(int i = 20 ; i >= 0 ; -- i) if(lca[u][i] != lca[v][i]) u = lca[u][i] , v = lca[v][i];
        return lca[u][0];
    }
    void build(int x,int fa)
    {
        root[x]=trie.insert(w[x],root[fa]);
        for(int i=0;i<E[x].size();i++)
        {
            int v = E[x][i];
            if(v==fa)continue;
            lca[v][0] = x , deep[v] = deep[x] + 1;
            build(v,x);
        }
    }
    
    int query(int x,int y,int w)
    {
        int pl = querylca(x,y);
        return max(trie.find(w,root[lca[pl][0]],root[x]),trie.find(w,root[lca[pl][0]],root[y]));
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&q)!=EOF)
        {
            init(n);
            for(int i=1;i<=n;i++)
                scanf("%d",&w[i]);
            for(int i=1;i<n;i++)
            {
                int x,y;scanf("%d%d",&x,&y);
                E[x].push_back(y);
                E[y].push_back(x);
            }
            build(1,0);
            for(int j = 1 ; j <= 20 ; ++ j)
                for(int i = 1 ; i <= n ; ++ i)
                    if(lca[i][j-1])
                        lca[i][j] = lca[lca[i][j-1]][j-1];
            for(int i=1;i<=q;i++)
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                printf("%d
    ",query(a,b,c));
            }
        }
    }
  • 相关阅读:
    用laravel写的项目如何布置在虚拟机上
    在Laravel中注册中间件
    ssh出错
    DB2单表导入导出
    DB2 还原数据库
    ssh-keygen 免交互
    DB2 命令
    21个项目玩转深度学习:基于TensorFlow的实践详解06—人脸检测和识别——数据集
    jieba—parallel
    更新数据
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5032592.html
Copyright © 2011-2022 走看看