zoukankan      html  css  js  c++  java
  • 字典树和可持久化字典树

    Trie

    (Trie)的结构非常好懂,我们用(delta(u,v))表示结点(u)(v)字符指向的下一个结点,或着说是结点(u)代表的字符串后面添加一个字符(c)形成的字符串的结点。((c)的取值范围和字符集大小有关,不一定是 (0 sim 26)。)

    (Trie)的简图:

    (Code)

    插入

    void insert(int x) //插入x
    {
      for (int i = 30, u = 1; i >= 0; --i) 
      {
        int c = ((x >> i) & 1);
        if (!ch[u][c]) ch[u][c] = ++tot;
        u = ch[u][c];
      }
    }
    

    查询

    void get(int x) {
      int res = 0;
      for (int i = 30, u = 1; i >= 0; --i) {
        int c = ((x >> i) & 1);
        if (ch[u][c ^ 1]) {
          u = ch[u][c ^ 1];
          res = ...... //根据题意求答案
        } else
          u = ch[u][c];
      }
      ans = std::max(ans, res);
    }
    

    可持久化字典树

    可持久化 (Trie) 的方式和可持久化线段树的方式是相似的,即每次只修改被添加或值被修改的节点,而保留没有被改动的节点,在上一个版本的基础上连边,使最后每个版本的 (Trie) 树的根遍历所能分离出的 (Trie) 树都是完整且包含全部信息的。

    大部分的可持久化 (Trie) 题中,(Trie) 都是以 (01-Trie) 的形式出现的。

    (Code)

    void update(int u,int v,int x)//新建版本u,上一个版本是v,插入x
    {
    	for (int i = 30; i >= 0; i--)
    	{
    		int c = (x >> i) & 1;
    		sum[u] = sum[v] + 1;//sum[x] 代表连x的边有多少个数经过
    		ch[u][c ^ 1] = ch[v][c ^ 1];
    		ch[u][c] = ++tot;
    		u = ch[u][c],v = ch[v][c];
    	}
    	sum[u] = sum[v] + 1;
    }
    

    查询区间,只需要利用前缀和和差分的思想,用两棵前缀 (Trie) 树(也就是按顺序添加数的两个历史版本)相减即为该区间的线段树。再利用动态开点的思想,不添加没有计算过的点,以减少空间占用。

    int query(int u,int v,int x)//求区间[u + 1,v]关于x的答案 
    {
    	int res = 0;
    	for (int i = 30; i >= 0; i--)
    	{
    		int c = (x >> i) & 1,p = sum[ch[v][c ^ 1]] - sum[ch[u][c ^ 1]];
    		if (p) res = ...........;//根据题意求答案
    		else u = ch[u][c],v = ch[v][c];
    	}
    	return res;
    }
    
  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/nibabadeboke/p/13448609.html
Copyright © 2011-2022 走看看