当前位置: 首页 > news >正文

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

 

转载于:https://www.cnblogs.com/qscqesze/p/5032592.html

相关文章:

  • Android项目之无线点餐(2)--用户登录的客户端和服务器端实现
  • 千变万化的ViewPager切换动画(1)--仅支持3.0以上版本的官方方法
  • Canopy聚类算法与Mahout中的实现
  • Android基础学习—下载并在Eclipse中关联Android源码
  • 【html】【11】函数名称约束规范
  • 千变万化的ViewPager切换动画(2)--自定义ViewPager的实现方法
  • 二叉树习题之重建二叉树
  • WebView的简单入门
  • 持续集成
  • Android开发Eclipse连接真机
  • 吐槽贴-微信公众号那些让人想起神兽的坑
  • No orientation specified, and the default is horizontal.
  • Java代码实现随机生成汉字
  • (转)负载均衡,回话保持,cookie
  • js跨域及解决方案
  • [case10]使用RSQL实现端到端的动态查询
  • Angular数据绑定机制
  • bootstrap创建登录注册页面
  • Node 版本管理
  • python学习笔记 - ThreadLocal
  • Python学习之路16-使用API
  • 聊聊flink的TableFactory
  • 聊聊sentinel的DegradeSlot
  • 软件开发学习的5大技巧,你知道吗?
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (70min)字节暑假实习二面(已挂)
  • (多级缓存)缓存同步
  • (排序详解之 堆排序)
  • (推荐)叮当——中文语音对话机器人
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)memcache、redis缓存
  • (转)程序员技术练级攻略
  • *1 计算机基础和操作系统基础及几大协议
  • .form文件_一篇文章学会文件上传
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET delegate 委托 、 Event 事件
  • .NET MVC第五章、模型绑定获取表单数据
  • .net反编译的九款神器
  • .NET企业级应用架构设计系列之开场白
  • .NET下ASPX编程的几个小问题
  • .net中的Queue和Stack
  • @Autowired @Resource @Qualifier的区别
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [Android] Amazon 的 android 音视频开发文档
  • [C++基础]-入门知识
  • [cocos2d-x]关于CC_CALLBACK
  • [Flutter]WindowsPlatform上运行遇到的问题总结
  • [Google Guava] 1.1-使用和避免null
  • [hibernate]基本值类型映射之日期类型
  • [java刷算法]牛客—剑指offer链表有环的入口、反转链表、合并排序链表
  • [lesson17]对象的构造(上)
  • [Oh My C++ Diary]\t \n \r的用法
  • [Qt桌面开发]一个Qt简单界面的开发