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\n",query(a,b,c));
        }
    }
}

 

    原文作者:qscqesze
    原文地址: https://www.cnblogs.com/qscqesze/p/5032592.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞